【leetcode】839. 相似字串組(similar-string-groups)(並查集)[困難]
連結
https://leetcode-cn.com/problems/similar-string-groups/
耗時
解題:26 min
題解:12 min
題意
如果交換字串 X 中的兩個不同位置的字母,使得它和字串 Y 相等,那麼稱 X 和 Y 兩個字串相似。如果這兩個字串本身是相等的,那它們也是相似的。
例如,“tars” 和 “rats” 是相似的 (交換 0 與 2 的位置); “rats” 和 “arts” 也是相似的,但是 “star” 不與 “tars”,“rats”,或 “arts” 相似。
總之,它們通過相似性形成了兩個關聯組:{“tars”, “rats”, “arts”} 和 {“star”}。注意,“tars” 和 “arts” 是在同一組中,即使它們並不相似。形式上,對每個組而言,要確定一個單詞在組中,只需要這個詞和該組中至少一個單詞相似。
給你一個字串列表 strs。列表中的每個字串都是 strs 中其它所有字串的一個字母異位詞。請問 strs 中有多少個相似字串組?
提示:
- 1 <= strs.length <= 100
- 1 <= strs[i].length <= 1000
- sum(strs[i].length) <= 2 * 104
- strs[i] 只包含小寫字母。
- strs 中的所有單詞都具有相同的長度,且是彼此的字母異位詞。
備註: 字母異位詞(anagram),一種把某個字串的字母的位置(順序)加以改換所形成的新詞。
思路
比較暴力的一個想法,對於每個字串遍歷字串列表中所有字串找與其相似的字串(即兩個字串中只有兩個字元不同或沒有字元不同)。使用並查集統計相似字串組的數量,初始時設定相似字串組的數量為字串列表的長度,合併所有相似字串,最終並查集中集合的數量即是答案(strs中相似字串組的數量)。
時間複雜度: O ( s u m ( s t r s [ i ] . l e n g t h ) ∗ s t r s . l e n g t h ) = O ( 1 0 6 ) O(sum(strs[i].length)*strs.length)=O(10^6) O(sum(strs[i].length)∗strs.length)=O(106)
AC程式碼
class Solution {
public:
constexpr static int MAXN = 110;
int father[MAXN]; // 儲存i的father父節點
int setcnt = 1;
void makeSet() {
for (int i = 0; i < MAXN; i++)
father[i] = i;
}
int findRoot(int x) { // 迭代找根節點
int root = x; // 根節點
while (root != father[root]) { // 尋找根節點
root = father[root];
}
while (x != root) {
int tmp = father[x];
father[x] = root; // 根節點賦值
x = tmp;
}
return root;
}
void Union(int x, int y) { // 將x所在的集合和y所在的集合整合起來形成一個集合。
int a, b;
a = findRoot(x);
b = findRoot(y);
if(a == b) return ;
father[a] = b; // y連在x的根節點上 或father[b] = a為x連在y的根節點上
setcnt--;
}
int numSimilarGroups(vector<string>& strs) {
int n = strs.size();
setcnt = n;
makeSet();
for(int i = 0; i < n; ++i) {
for(int j = i+1; j < n; ++j) {
string stra = strs[i];
string strb = strs[j];
int diffnum = 0;
for(int k = 0; k < stra.size(); ++k) {
if(stra[k] != strb[k]) {
diffnum++;
if(diffnum > 2) {
break;
}
}
}
if(diffnum == 0 || diffnum == 2) {
Union(i, j);
}
}
}
return setcnt;
}
};