题目
思路:
- 一个相似字符组的条件是数组中至少有一个字符和你相似,相当于具有关联关系,这样数组中的相关关系可以形成一段连通的关系网
- 这样我们就可以使用并查集去合并这些有关系的字符,最后返回连通组的个数,即为相似字符组的个数
- 判断是否为相似字符,只需逐位比较,当不同的数量超过2个时(大于等于2)两个字符不相似(相当也相似)
==================== 下面简单介绍一下并查集 ======================================
并查集三步曲
● 定义一个大小为结点总数的数组(用于记录节点下标)
int[] pre;
pre = new int[n];
● find函数
int find(int x) //查找x的掌门
{
int r=x; //委托 r 去找掌门
while(pre[r] != r){ //如果r的上级不是r自己(也就是说找到的大侠他不是掌门 = =)
r = pre[r];
} // r 接着找他的上级,直到找到掌门为止。
return r ; //掌门驾到~~~
}
- 简易版
public int find(int x){
return pre[x]==x ? x:find(pre[x]);
}
● join函数 (用于合并祖先)
void join(int x,int y)
{
int fx=find(x), fy=find(y); //如果两个未合并,将两个合并
if(fx != fy){
pre[fx]=fy;
}else{
sout("父节点相同")
}
}
● 查找连通数
for (int i = 0; i < n; i++) {
if (pre[i] == i) {
ans++;
}
}
代码:
class Solution {
public int numSimilarGroups(String[] strs) {
//初始化连通图的数量
int ans=0;
UnionFind unionFind = new UnionFind(strs.length);
for (int i = 0; i < strs.length; i++) {
for (int j = i+1; j < strs.length; j++) {
if(!istrue(strs[i],strs[j])){
continue;
}
//两人的祖先不同就合并
if (unionFind.find(i)!=unionFind.find(j)){
unionFind.join(i,j);
}
}
}
for (int i = 0; i < strs.length; i++) {
//找到连通的首个字符串
if (unionFind.find(i)==i){
ans++;
}
}
return ans;
}
public boolean istrue(String str1,String str2){
int num=0;
for (int i = 0; i <str1.length() ; i++) {
if (str1.charAt(i)!=str2.charAt(i)){
num++;
}
}
return num<=2;
}
class UnionFind {
// pre[i] 表示 节点i的父节点
int[] pre;
public UnionFind(int num){
pre=new int[num];
// 自己的父节点为自己
for (int i = 0; i < num; i++) {
pre[i]=i;
}
}
public void join(int x,int y){
int x1=find(x);
int y1=find(y);
if (x1!=y1){
//随机将两节点的父节点合并,y1的父节点为x1
pre[y1]=x1;
}else {
System.out.println("两父节点相同");
}
}
public int find(int x){
return pre[x]==x ? x:find(pre[x]);
}
}
}