990. Satisfiability of Equality Equations
Given an array equations of strings that represent relationships between variables, each string equations[i] has length 4 and takes one of two different forms: “a==b” or “a!=b”. Here, a and b are lowercase letters (not necessarily different) that represent one-letter variable names.
Return true if and only if it is possible to assign integers to variable names so as to satisfy all the given equations.
Example 1:
Input: ["a==b","b!=a"]
Output: false
Explanation: If we assign say, a = 1 and b = 1, then the first equation is satisfied, but not the second. There is no way to assign the variables to satisfy both equations.
Example 2:
Input: ["b==a","a==b"]
Output: true
Explanation: We could assign a = 1 and b = 1 to satisfy both equations.
Example 3:
Input: ["a==b","b==c","a==c"]
Output: true
Example 4:
Input: ["a==b","b!=c","c==a"]
Output: false
Example 5:
Input: ["c==c","b==d","x!=z"]
Output: true
Note:
1 <= equations.length <= 500
equations[i].length == 4
equations[i][0] and equations[i][3] are lowercase letters
equations[i][1] is either '=' or '!'
equations[i][2] is '='
方法1: Union Find
思路:
因为限定在单个字符,用一个26单位长的向量来记录祖先。第一遍遍历等式,建立所有union。第二遍遍历所有不等式,如果有相同祖先的两个数在这里强制不等,则返回false。否则遍历结束返回true。
易错点:
Example: ["b==b","e==c","e==c","d!=e"]
if (a == b) continue;
要排除在union时 ,也就是第一遍find的时候b == b的情况。这时如果不continue,会出现第二遍find中死循环的情况。因为第一遍union操作中错误的将为自己的祖先指向自己(应该保持-1不变),且一定不为-1,find不会终止。while (roots[i] ! = -1 && roots[i] )
如果两个相同等式在union过程中重复出现,此时c和b的祖先都是b,roots[x] = y 会将b指向自己,同理在find中死循环
NOTE: 为了防止这种情况发生,最好都initialize成 roots[i] = i,而判断条件就简化为while (roots[i] != i )
class Solution {
public:
bool equationsPossible(vector<string>& equations) {
vector<int> roots(26, -1);
for (int i = 0; i < 26; i++){
roots[i] = i;
}
for (auto eq: equations){
if (eq[1] == '='){
int a = int(eq[0] - 'a');
int b = int(eq[3] - 'a');
if (a == b) continue;
int x = find(roots, a);
int y = find(roots, b);
roots[x] = y;
}
}
// printVector(roots);
for (auto eq: equations){
if (eq[1] == '!'){
int a = int(eq[0] - 'a');
int b = int(eq[3] - 'a');
int x = find(roots, a);
int y = find(roots, b);
if (x == y){
return false;
}
}
}
return true;
}
int find(vector<int> & roots, int i){
// while (roots[i] != -1 && roots[i] != i){
while (roots[i] != i){
i = roots[i];
}
return i;
}
void printVector(vector<int> & v){
for (int a : v){
cout << a << " ";
}
cout << endl;
}
};
discussion的简洁版,原理一样:https://leetcode.com/problems/satisfiability-of-equality-equations/discuss/234486/JavaC%2B%2BPython-Easy-Union-Find
int uf[26];
bool equationsPossible(vector<string>& equations) {
for (int i = 0; i < 26; ++i) uf[i] = i;
for (string e : equations)
if (e[1] == '=')
uf[find(e[0] - 'a')] = find(e[3] - 'a');
for (string e : equations)
if (e[1] == '!' && find(e[0] - 'a') == find(e[3] - 'a'))
return false;
return true;
}
int find(int x) {
if (x != uf[x]) uf[x] = find(uf[x]);
return uf[x];
}