如果我们交换字符串 X 中的两个不同位置的字母,使得它和字符串 Y 相等,那么称 X 和 Y 两个字符串相似。如果这两个字符串本身是相等的,那它们也是相似的。
例如,"tars" 和 "rats" 是相似的 (交换 0 与 2 的位置); "rats" 和 "arts" 也是相似的,但是 "star" 不与 "tars","rats",或 "arts" 相似。
总之,它们通过相似性形成了两个关联组:{"tars", "rats", "arts"} 和 {"star"}。注意,"tars" 和 "arts" 是在同一组中,即使它们并不相似。形式上,对每个组而言,要确定一个单词在组中,只需要这个词和该组中至少一个单词相似。
我们给出了一个不包含重复的字符串列表 A。列表中的每个字符串都是 A 中其它所有字符串的一个字母异位词。请问 A 中有多少个相似字符串组?
示例:
输入:["tars","rats","arts","star"]
输出:2
题目理解:通过字符串相似的定义,隐性的定义一种关系,符合的才有无向边的存在, 根据边将能能 串联到 一块的节点聚为一簇。
题目本质:深度搜索,将有关系的边找出来并加以标记 。
应用:将 有边关系的节点分别聚类找出来
问题:深度递归一次将能 递归到的全给遍历到了,for循环的则是没有递归 到的。状态的传递。 状态的传递类似于 并查集,同类同簇的同一个标记
class Solution {
private boolean isSimilar(String a,String b){
int res=0;
for (int i=0;i<a.length();i++){
if(a.charAt(i)!=b.charAt(i)){
res++;
}
}
return res==2|res==0;
}
// public boolean isSimilar(String s,String t){
// int res = 0, i = 0;
// while(res <= 2 && i < s.length()){
// if(s.charAt(i) != t.charAt(i)) res++;
// i++;
// }
// return res == 2;
// }
private void dfs(String[] a,int index,boolean[] visited,int[] flags){
// if(visited[index]){
// return;
// }
for(int i=0;i<a.length;i++){
if(index==i| flags[i]!=-1){
continue;
}
if(this.isSimilar(a[i],a[index])){
flags[i]=flags[index];
this.dfs(a,i,visited,flags);
visited[i]=true;
}
}
}
public int numSimilarGroups(String[] A) {
boolean[] visited=new boolean[A.length];
int[] flags=new int[A.length];
Arrays.fill(visited,false);
Arrays.fill(flags,-1);
for(int i=0;i<A.length;i++){
if(flags[i]==-1){
flags[i]=i;
}
this.dfs(A,i,visited,flags);
visited[i]=true;
}
HashSet<Integer> numberSet=new HashSet<>();
for(int i=0;i<flags.length;i++){
numberSet.add(flags[i]);
}
return numberSet.size();
}
}