给定一个由表示变量之间关系的字符串方程组成的数组,每个字符串方程 equations[i] 的长度为 4,并采用两种不同的形式之一:"a==b" 或 "a!=b"。在这里,a 和 b 是小写字母(不一定不同),表示单字母变量名。
只有当可以将整数分配给变量名,以便满足所有给定的方程时才返回 true,否则返回 false。
示例 1:
输入:["a==b","b!=a"]
输出:false
解释:如果我们指定,a = 1 且 b = 1,那么可以满足第一个方程,但无法满足第二个方程。没有办法分配变量同时满足这两个方程。
示例 2:
输入:["b==a","a==b"]
输出:true
解释:我们可以指定 a = 1 且 b = 1 以满足满足这两个方程。
示例 3:
输入:["a==b","b==c","a==c"]
输出:true
示例 4:
输入:["a==b","b!=c","c==a"]
输出:false
示例 5:
输入:["c==c","b==d","x!=z"]
输出:true
我自己做的时候只想到了用集合,但是无法处理当两个变量都不属于任何一个集合的时候,怎么选择插入哪个集合。
这题考察并查集知识,很遗憾在看答案前我没有想起数据结构课程上学的内容。看了后很快就想起来了,说明上课还是有用的嘛,不一定一直记得,但是再看一遍相关内容就能很快唤醒大脑的记忆细胞。并查集主要有查找find()和构造unite()两个函数,具体实现通过一个数组记录父节点信息,同一个集合所有节点的根节点相同,当一个节点的父节点是它本身时,说明该节点是根节点。构造并查集时则将第一个变量的根节点的父节点指向第二个变量的根节点,这样两个变量都指向同一个根节点,即属于同一个并查集。
遍历两遍字符串数组,第一遍遍历的时候根据'=='来建立并查集,第二遍的时候根据’!=‘进行判断,如果两个变量的根节点相同,则返回false。
class Solution {
vector<int> parent;
public:
Solution(){
for(int i=0;i<26;i++){
parent.push_back(i);
}
}
bool equationsPossible(vector<string>& equations) {
int len=equations.size();
for(int i=0;i<len;i++){
if(equations[i][1]=='='){
int num1=equations[i][0]-'a';
int num2=equations[i][3]-'a';
unite(num1,num2);
}
}
for(int i=0;i<len;i++){
if(equations[i][1]=='!'){
int num1=equations[i][0]-'a';
int num2=equations[i][3]-'a';
if(find(num1)==find(num2))
return false;
}
}
return true;
}
int find(int idx){
if(parent[idx]==idx)
return idx;
parent[idx]=find(parent[idx]);
return parent[idx];
}
void unite(int idx1,int idx2){
parent[find(idx1)]=find(idx2);
}
};
注意开始的时候我是直接 vector<int>parent(26,0)来初始化parent数组的,但是报错,查了一下说是在类内只能用等号初始化即复制构造函数和初始化列表进行初始化。可以改成vector<int>parent{0,1,2...24,25}。但是好傻,不如直接像上面代码那样。