399.除法求值

解题思路
本题已知一个变量对数组,一个实数值数组,其中变量对数组表示等式左边,而实数值数组表示等式右边的结果;而数组queries则表示等式左边,需要我们根据上述已知的变量对数组以及实数值数组得到这个等式右边的结果。如果不存在就返回-1。
本题我们需要用图来做,建立被除数,除数,商的有向图。我们使用邻接表来实现,unordered_map<string, vector<pair<string, double>>> graph;
从题目中可以看到被除数和除数都是以字符串的形式进行存储的,所以这里我们给他们的类型就是string。
a / b = 2.0 <=========> graph["a"] = {"b", 2.0}
那么我们就需要根据题目中给出的equations和values进行建图,
建图具体做法如下:
遍历i个等式,取出第i个等式的被除数和除数,取出相应的value值,存入graph,同时反向的也存储一下,就是b / a = 0.5;
递归遍历:
对于题目中的queries,我们需要从上面建好的图中去递归遍历。取queries中的第j个问题的2个数分别为start和end。
终止条件:
当start==end时,说明在图中找到了这条链路,返回这条链路的乘积即可;
递归:用unordered_set来存储访问过的start数,记作visited,取对应的图graph中相邻的除数中是否存在于visited中,若存在,则说明这条路已经走过,继续往下走;若不存在,则递归遍历除数的邻居,观察是否有链路达到end。
如果返回的乘积不为-1.0,则说明我们找到了当前值的下一个节点之间的链路,返回相应的值,继续递归。
如果遍历所有结果都没有结果,说明graph中不存在start到end的链路,则直接返回-1.0。
查询遍历:
先查看queries中的字符是否存在于graph中,不存在返回-1.0,如果存在被除数和除数相同则返回1.0,其余的用递归来处理结果,初始传入product=1.0,这样不会影响之后的路径权重的乘积。
代码
python
python
class Solution(object):
def calcEquation(self, equations, values, queries):
"""
:type equations: List[List[str]]
:type values: List[float]
:type queries: List[List[str]]
:rtype: List[float]
"""
graph = defaultdict(list)
# 1.建图
for (a, b), val in zip(equations, values):
graph[a].append((b, val))
graph[b].append((a, 1.0/val))
# 查询
def dfs(start, end, visited, product):
# 终止条件
if start == end:
return product
visited.add(start)
for neighbor,weight in graph[start]:
if neighbor not in visited:
ans = dfs(neighbor, end, visited, product * weight)
# 只要找到一个有效路径就立即返回,否则继续尝试
if ans != -1.0:
return ans
# 说明不存在start到end的路径
return -1.0
res = []
# 判断是否在图中
for a,b in queries:
if a not in graph or b not in graph:
res.append(-1.0)
continue
if a==b:
res.append(1.0)
continue
visited= set()
# 递归查询
ans = dfs(a, b, visited, 1.0)
res.append(ans)
return res
C++
cpp
class Solution {
public:
// 邻接表,存储graph graph[u] -> (v, weight) 表示 u / v = weight
unordered_map<string, vector<pair<string, double>>> graph;
double dfs(string start, string end, unordered_set<string> &visited, double product)
{
// 终止条件 当start==end的时候,返回整条链路的乘积
if(start==end)
return product;
visited.insert(start);
// 取出graph中对应的除数
for(auto &p : graph[start])
{
string next = p.first;
double val = p.second;
// 如果visited中没有next,那么find()迭代器就会返回visited.end()
// 说明next没有访问过,继续递归
if(visited.find(next)==visited.end())
{
double res = dfs(next, end, visited, product * val);
// 一旦res=-1.0,说明这个邻居不行,换下一个邻居继续判断
// 不等于-1.0,返回当前邻居结果,继续下一层遍历
if(res!=-1.0)
return res;
}
// 说明next存在visited中,继续递归
}
// 遍历所有结果都没有,说明graph中不存在从start到end的链路,返回-1.0
return -1.0;
}
vector<double> calcEquation(vector<vector<string>>& equations, vector<double>& values, vector<vector<string>>& queries) {
// 1. 建图
for(int i=0;i<equations.size();i++)
{
// 取出被除数和除数
string a = equations[i][0];
string b = equations[i][1];
// 取出相应的商
double val = values[i];
// 存入图中
graph[a].push_back({b, val});
graph[b].push_back({a, 1/val});
}
// 2. 递归得到乘积结果
vector<double> res;
for(int j=0;j<queries.size();j++)
{
string start = queries[j][0];
string end = queries[j][1];
// 被除数和除数二者之一不存在graph中,直接返回-1.0
if(graph.find(start)==graph.end() || graph.find(end)==graph.end())
{
res.push_back(-1.0);
continue;
}
// 被除数和除数相同,则直接返回1.0
if(start==end)
{
res.push_back(1.0);
continue;
}
// 进入递归处理结果
unordered_set<string> visited;
double ans = dfs(start, end, visited, 1.0);
res.push_back(ans);
}
return res;
}
};