Leetcode之相似字符串组

本文介绍了一种使用宽度优先遍历(BFS)和并查集(Disjoint Set)来解决字符串相似组的问题。示例中展示了如何判断两个字符串是否相似,并通过这两种方法找出给定字符串列表中的所有相似字符串组。在给定的示例输入下,算法能够正确地计算出相似字符串组的数量。这种方法对于处理字母异位词和构建连通图的概念提供了清晰的解释。
摘要由CSDN通过智能技术生成

题目:

如果交换字符串 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
示例 2:

输入:strs = ["omv","ovm"]
输出:1

提示:

1 <= strs.length <= 300
1 <= strs[i].length <= 300
strs[i] 只包含小写字母。
strs 中的所有单词都具有相同的长度,且是彼此的字母异位词。

备注:

      字母异位词(anagram),一种把某个字符串的字母的位置(顺序)加以改换所形成的新词。

代码:

方法一——宽度优先遍历(bfs):

class Solution {
public:
bool judge(string a,string b){
    int count=0;
    int len=a.length();
    for(int i=0;i<len;i++){
        if(a[i]!=b[i]){
            count+=1;
        }
    }
    return count==0||count==2;
}

int numSimilarGroups(vector<string>& strs) {
    int slen=strs.size();

    vector<bool> visited(slen,false);
    int count=0;
    for(int k=0;k<slen;k++){
        if(!visited[k]){
            count+=1;
            queue<int> q;
            q.push(k);
            visited[k]=true;
            while(!q.empty()){
                int qsize=q.size();
                for(int i=0;i<qsize;i++){
                    int temp=q.front();q.pop();
                    for(int j=0;j<strs.size();j++){
                        if(visited[j])continue;
                        if(judge(strs[temp],strs[j])){
                            q.push(j);
                            visited[j]=true;
                        }
                    }
                }
            }
        }
    }
    return count;
}

};

思路:

遍历所有没有被访问的字符串,每一个字符串都通过bfs,queue的方式,找它所有的相邻字符串,并标记为visited。通过技术,从循环进入访问了多少个字符串,这个次数,就是连通图的个数。

方法二——并查集,连通图

class Solution {
public:
int findroot(vector<int>& indexs,int i){
    if(indexs[i]==i)return i;
    int r= findroot(indexs,indexs[i]);
    indexs[i]=r;
    return r;
}

void insert(vector<int>& indexs,int i,int j){
    int ri= findroot(indexs,i);
    int rj= findroot(indexs,j);
    if(ri==rj)return;
    if(ri>rj){
        indexs[ri]=rj;
    }else{
        indexs[rj]=ri;
    }
}
bool judge(string a,string b){
    int count=0;
    int len=a.length();
    for(int i=0;i<len;i++){
        if(a[i]!=b[i]){
            count+=1;
        }
    }
    return count==0||count==2;
}

int numSimilarGroups(vector<string>& strs) {
    int slen=strs.size();
    vector<int> indexs(slen,0);
    for(int i=0;i<slen;i++){
        indexs[i]=i;
    }

    for(int i=0;i<slen;i++){
        for(int j=i+1;j<slen;j++){
            if(findroot(indexs,i)== findroot(indexs,j))continue;
            if(judge(strs[i],strs[j])){
                insert(indexs,i,j);
            }
        }
    }

    set<int> s;
    for(int i=0;i<slen;i++){
        int r= findroot(indexs,i);
        if(!s.count(r)){
            s.insert(r);
        }
    }
    return s.size();
}
};

思路:两两遍历所有可能的字符串对,如果两个字符串只有两个字母不同或者全部相同,即相似,那么把他们插到并查集中。最后使用一个set统计,并查集中,有多少个不同的根的数目,这个就是题目中的不同相似字符串组的个数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值