给定一个由表示变量之间关系的字符串方程组成的数组,每个字符串方程 equations[i]
的长度为 4
,并采用两种不同的形式之一:"a==b"
或 "a!=b"
。在这里,a 和 b 是小写字母(不一定不同),表示单字母变量名。
只有当可以将整数分配给变量名,以便满足所有给定的方程时才返回 true
,否则返回 false
。
示例 1:
1 2 3
| 输入:["a==b","b!=a"] 输出:false 解释:如果我们指定,a = 1 且 b = 1,那么可以满足第一个方程,但无法满足第二个方程。没有办法分配变量同时满足这两个方程。
|
示例 2:
1 2 3
| 输出:["b==a","a==b"] 输入:true 解释:我们可以指定 a = 1 且 b = 1 以满足满足这两个方程。
|
示例 3:
1 2
| 输入:["a==b","b==c","a==c"] 输出:true
|
示例 4:
1 2
| 输入:["a==b","b!=c","c==a"] 输出:false
|
示例 5:
1 2
| 输入:["c==c","b==d","x!=z"] 输出:true
|
提示:
1 <= equations.length <= 500
equations[i].length == 4
equations[i][0]
和 equations[i][3]
是小写字母
equations[i][1]
要么是 '='
,要么是 '!'
equations[i][2]
是 '='
由于相等关系具有传递性,所有相等的变量属于同一个集合,只关心连通性,不关心距离,因此很容易想到并查集。
算法流程:
- 扫描所有等式,将等式两边的顶点进行合并;
- 再扫描所有不等式,检查每一个不等式的两个顶点是不是在一个连通分量里:
- 如果在,代表 a == b 和 a != b 同时成立,返回 false
- 如果所有检查都没有矛盾,返回 true
使用一个数组 parent 存储每个变量的连通分量信息,其中的每个元素表示当前连通分量的父节点信息,如果父节点是自身,说明该变量为所在连通分量的根结点。一开始所有变量的父节点都是它们自身。对于合并操作,我们将第一个变量的根结点的父节点指向第二个变量的根结点;对于查找操作,我们沿着当前变量的父节点一路向上查找,直到找到根结点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| class Solution { public boolean equationsPossible(String[] equations) { UnionFind unionFind = new UnionFind(26);
for(String equation : equations){ char[] charArray = equation.toCharArray(); if(charArray[1] == '='){ int index1 = charArray[0] - 'a'; int index2 = charArray[3] - 'a'; unionFind.union(index1, index2); } }
for(String equation : equations){ char[] charArray = equation.toCharArray(); if(charArray[1] == '!'){ int index1 = charArray[0] - 'a'; int index2 = charArray[3] - 'a'; if(unionFind.isConnected(index1, index2)){ return false; } } } return true; }
private class UnionFind{ private int[] parent;
public UnionFind(int n){ parent = new int[n]; for(int i = 0; i < n; i++){ parent[i] = i; } }
public int find(int x){ while(x != parent[x]){ parent[x] = parent[parent[x]]; x = parent[x]; } return x; }
public void union(int x, int y){ int rootX = find(x); int rootY = find(y); parent[rootX] = rootY; }
public boolean isConnected(int x, int y){ return find(x) == find(y); } }
}
|
时间复杂度 O(n + ClogC),其中 n 是 equations 中的方程数量,C 是变量的总数,本题中变量都是小写字母即 C<=26。并查集代码中使用了路径压缩算法,对于每个方程的合并和查找的均摊时间复杂度都是 O(logC)。
空间复杂度 O(C),创建一个 parent 数组存储每个变量的连通分量信息。