如果交换字符串 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 = ["tars","rats","arts","star"] 输出:2
分析:
首先解决两个字符串是否相似的问题,由于给出的字符串互相是字母异位词,所以只需要判定字符串相同位置为不同字符的数目,若为0或2则两个字符串相似,否则一定不相似。
然后对给出的字符串数组进行俩俩比对,若字符串相似,则在并查集中将这两个字符串进行合并,合并后这两个字符串的根字符串一致代表他们在同一组关系中。求相似字符串组即求并查集中不同合并关系的数目。
class Solution {
int[] pre;
int find(int x){
while(x != pre[x]){
x = pre[x];
}
return x;
}
void union(int x, int y){
int x1 = find(x);//x的根,即祖先赋值给x1
int y1 = find(y);//y的根,即祖先赋值给y1
//如果两个不属于同一个根,即两个人不是一个祖宗,比如一个姓朱,一个姓李
//姓朱的和姓李的不可能是一个祖先吧,但是这两家又产生了关系,比如联姻
//例如姓朱的男青年和姓李的黄花大闺女结婚了
//在古代的时候,”嫁鸡随鸡嫁狗随狗“女性是要跟随丈夫的姓氏,所以李姓闺女就要叫做”朱氏“
if(x1 != y1){
pre[x1] = y1;
}
}
//以上为并查集模板
public int numSimilarGroups(String[] strs) {
int n = strs.length;
pre = new int[n];
for(int i = 0; i < n; i++) pre[i] = i;//初始化
for(int i = 0; i < n; i++){
for(int j = i + 1; j < n; j++){
if(check(strs[i], strs[j])){//检查两个字符串是否是相似关系
union(i, j);
}
}
}
int res = 0;
for(int i = 0; i < n; i++){
if(pre[i] == i)
res++;
}
return res;
}
boolean check(String a, String b){
int cnt = 0;
int n = a.length();
for(int i = 0; i < n; i++){
if(a.charAt(i) != b.charAt(i))
cnt ++;
}
return cnt <= 2;
}
}