image.png

    1. class Solution {
    2. public double[] calcEquation(List<List<String>> equations, double[] values, List<List<String>> queries) {
    3. int equationsSize = equations.size();
    4. UnionFind unionFind = new UnionFind(2 * equationsSize); //最大需要两倍空间(每个list有两个字母)
    5. //第一步,预处理,将变量的值与id进行映射,使得并查集的底层用数组实现,方便编码
    6. Map<String, Integer> map = new HashMap<>(2 * equationsSize);//初始化map将字母关系转化为数字
    7. int id = 0; //对应values中索引和映射字母
    8. for (int i = 0; i < equationsSize; i++) {
    9. List<String> equation = equations.get(i);
    10. String var1 = equation.get(0);
    11. String var2 = equation.get(1);
    12. if (!map.containsKey(var1)) {
    13. map.put(var1, id++);
    14. }
    15. if (!map.containsKey(var2)) {
    16. map.put(var2, id++);
    17. }
    18. //并查询查询之前执行一次合并操作
    19. unionFind.union(map.get(var1), map.get(var2), values[i]);
    20. }
    21. //第二步 做查询
    22. int queriesSize = queries.size();
    23. double[] res = new double[queriesSize];
    24. for (int i = 0; i < queriesSize; i++) {
    25. String var1 = queries.get(i).get(0);
    26. String var2 = queries.get(i).get(1);
    27. //得到需要查询的字母对应的id
    28. Integer id1 = map.get(var1);
    29. Integer id2 = map.get(var2);
    30. if (id1 == null || id2 == null) {
    31. res[i] = -1.0;
    32. } else {
    33. //两个节点都存在,则转化为和父节点的关系进行比较
    34. res[i] = unionFind.isConnected(id1, id2);
    35. }
    36. }
    37. return res;
    38. }
    39. class UnionFind {
    40. private int[] parent; //表示每个节点对应的父节点的id
    41. private double[] weight; //表示节点指向父节点的权值
    42. public UnionFind(int n) {
    43. this.parent = new int[n];
    44. this.weight = new double[n];
    45. //初始化,所有的父节点开始都是指向自己
    46. for (int i = 0; i < n; i++) {
    47. parent[i] = i;
    48. weight[i] = 1.0d;
    49. }
    50. }
    51. /**
    52. * 合并操作
    53. *
    54. * @param x,y 两个节点
    55. * @param value 有向边的权值
    56. */
    57. public void union(int x, int y, double value) {
    58. //找到两个节点对应的父节点
    59. int rootx = find(x);
    60. int rooty = find(y);
    61. if (rootx == rooty) {
    62. return;
    63. }
    64. parent[rootx] = rooty;
    65. weight[rootx] = weight[y] * value / weight[x];
    66. }
    67. /**
    68. * 路径压缩
    69. *
    70. * @param id 输入节点的id
    71. * @return 根节点的id
    72. */
    73. private int find(int id) {
    74. if (id != parent[id]) {
    75. //根据上一次节点的权值来更新当前节点的权值
    76. int preNode = parent[id];
    77. parent[id] = find(parent[id]);
    78. weight[id] *= weight[preNode];
    79. }
    80. return parent[id];
    81. }
    82. public double isConnected(int x, int y) {
    83. int rootX = find(x);
    84. int rootY = find(y);
    85. if (rootX == rootY) {
    86. return weight[x] / weight[y];
    87. } else {
    88. //说明不在一个集合中
    89. return -1;
    90. }
    91. }
    92. }
    93. }

    hot100-除法求值