1、题目描述
给你一个变量对数组 equations 和一个实数值数组 values 作为已知条件,其中 equations[i] = [Ai, Bi] 和 values[i] 共同表示等式 Ai / Bi = values[i] 。每个 Ai 或 Bi 是一个表示单个变量的字符串。
另有一些以数组 queries 表示的问题,其中 queries[j] = [Cj, Dj] 表示第 j 个问题,请你根据已知条件找出 Cj / Dj = ? 的结果作为答案。
返回 所有问题的答案 。如果存在某个无法确定的答案,则用 -1.0 替代这个答案。
注意:输入总是有效的。你可以假设除法运算中不会出现除数为 0 的情况,且不存在任何矛盾的结果。
示例 1:
输入:equations = [["a","b"],["b","c"]], values = [2.0,3.0], queries = [["a","c"],["b","a"],["a","e"],["a","a"],["x","x"]]
输出:[6.00000,0.50000,-1.00000,1.00000,-1.00000]
解释:
条件:a / b = 2.0, b / c = 3.0
问题:a / c = ?, b / a = ?, a / e = ?, a / a = ?, x / x = ?
结果:[6.0, 0.5, -1.0, 1.0, -1.0 ]
2、题目分析
-
原题的意思是equations的每个子集的两个元素之间存在关系,相除的结果在数组values的对应位置中,比如equations.get(0).get(0) / equations.get(0).get(1) = a / b = 2.0。之后求queries的每个子集的计算结果,比如
a / c = (a / b ) * (b / c)。
-
什么数据结构能很好的传达这种关系呢?图结构,每条有向边的权重就是相除的结果,寻找两个点相处的结果就是两个点路径的权重和。
-
怎么表示图呢?用一个二维数组记录两个点之间的权重,没有联系的两个点之间的权重值为-1.0
-
借助于前提条件和Floyd算法能求出任意两个点之间的距离(权重积)
3、代码实现
class Solution {
public double[] calcEquation(List<List<String>> equations, double[] values, List<List<String>> queries) {
Map<String,Integer> map1 = new HashMap<>();//记录每个节点为键对应的唯一值
int point_count = 0;//记录已知条件中出现的点的个数
for(int i = 0;i < equations.size();i++){
if(!map1.containsKey(equations.get(i).get(0)))
map1.put(equations.get(i).get(0),point_count++);
if(!map1.containsKey(equations.get(i).get(1)))
map1.put(equations.get(i).get(1),point_count++);
}
double[][] graph = new double[point_count][point_count];//记录点之间的权重
for(int i = 0;i < point_count;i++){//图初始化
for(int j = 0;j < point_count;j++){
graph[i][j] = -1.0;
}
}
for(int i = 0;i < equations.size();i++){//已知条件给图赋值
int va = map1.get(equations.get(i).get(0)),vb = map1.get(equations.get(i).get(1));
graph[va][vb] = values[i];
graph[vb][va] = 1.0 / values[i];
}
for(int k = 0;k < point_count;k++){//Floyd算法
for(int i = 0;i < point_count;i++){
for(int j = 0;j < point_count;j++){
if(graph[i][k] > 0 && graph[k][j] > 0){
graph[i][j] = graph[i][k] * graph[k][j];
}
}
}
}
double[] res = new double[queries.size()];//保存结果
for(int i = 0;i < queries.size();i++){
List<String> list = queries.get(i);
double cur = -1.0;//没有联系的点之间-1.0
if(map1.containsKey(list.get(0)) && map1.containsKey(list.get(1))){
int va = map1.get(list.get(0)),vb = map1.get(list.get(1));
if(graph[va][vb] > 0) cur = graph[va][vb];//有联系就更新结果
}
res[i] = cur;//赋值
}
return res;//返回结果
}
}
4、复杂度分析
- 时间复杂度:O(ML+N^3+QL)。构建图需要 O(ML)的时间;Floyd 算法需要 O(N^3)的时间;处理查询时,单次查询只需要 O(L)的字符串比较以及常数时间的额外操作。
- 空间复杂度:O(NL+N^2)。