問題描述
給定一個由表示變量之間關係的字符串方程組成的數組,每個字符串方程 equations[i]
的長度爲 4
,並採用兩種不同的形式之一:"a==b"
或 "a!=b"
。在這裏,a 和 b 是小寫字母(不一定不同),表示單字母變量名。
只有當可以將整數分配給變量名,以便滿足所有給定的方程時才返回 true
,否則返回 false
。
示例 1:
輸入:[“a==b”,“b!=a”]
輸出:false
解釋:如果我們指定,a = 1 且 b = 1,那麼可以滿足第一個方程,但無法滿足第二個方程。沒有辦法分配變量同時滿足這兩個方程。
解題報告
並查集主要用於解決一些元素分組的問題。它管理一系列不相交的集合,並支持兩種操作
- 合併(Union):把兩個不相交的集合合併爲一個集合
- 查詢(Find):查詢兩個元素是否在同一集合中。
算法步驟:
- 將所有具有相等關係的字母進行
merge
。 - 然後遍歷所有不相等的關係,如果發現不相等的兩個字母在同一個集合中,那麼直接返回
false
同時使用了 路徑壓縮 和 按秩合併 的優化策略。
實現代碼
class Solution{
public:
unordered_map<int, int>parent, cnt;
int find(int index){
return parent[index]==index?index:parent[index]=find(parent[index]);
}
void merge(int a, int b){
a=find(a);
b=find(b);
if(a==b) return;
// 按秩合併,爲了使得合併後的子樹高度儘量低,
// 需要把高度曉得那棵子樹接在高度高的那個樹下
if(cnt[a]<cnt[b]){
parent[a]=b;
cnt[b]+=cnt[a];
}
else{
parent[b]=a;
cnt[a]+=cnt[b];
}
}
bool equationsPossible(vector<string>&equations){
for(int i=0;i<26;i++){
parent[i]=i;
cnt[i]=1;
}
for (const string& str: equations) {
if (str[1] == '=') {
int index1 = str[0] - 'a';
int index2 = str[3] - 'a';
merge(index1, index2);
}
}
for (const string& str: equations) {
if (str[1] == '!') {
int index1 = str[0] - 'a';
int index2 = str[3] - 'a';
if (find(index1) == find(index2)) {
return false;
}
}
}
return true;
}
};
參考資料
[1] Leetcode 990. 等式方程的可滿足性
[2] 算法學習筆記(1) : 並查集
[3]