leetcode:839. 相似字符串组

题目来源

题目描述

在这里插入图片描述

class Solution {
public:
    int numSimilarGroups(vector<string>& strs) {

    }
};

题目解析

题目大意:给出一个字符串数组,要求找出这个数组中,“不相似”的字符串有多少种?

“相似字符串”的定义:

  • 如果A和B字符串只需要交换一次字母的位置就能变成两个相等的字符串,那么A和B是相似的
  • 即:A和B相似,有两种情况:
    • A == B
    • A和B只有两个字符不相等,其他字符都相等,这样交换一次才能完全相等
  • 而且题目中说了,字符串数组是“字母异位词”,即字符的种类和个数都完全一样,只是顺序不同

那么,什么叫做“相似字符串组呢”?即相似字符串组中的每个字符串都有另外至少一个字符串和它相似。比如对于 {“tars”, “rats”, “arts”} 这个相似字符串组而言,相似关系是 “tars” <=> “rats” <=> “arts” 。

可以看到“相似字符串组之间的关系有传递性,对于这种群组分类问题,是并查集的经典应用场合:

  • 我们可以将每个字符串看成是一个节点
  • 如果两个字符串相似,就将它们merge
  • 最后数有多少个联通分量即可。

怎么判断字符串A和字符串B是否相似呢?
,只要按位置对比字符,若不相等则 diff 自增1,若 diff 大于2了直接返回 false,因为只有 diff 正好等于2或者0的时候才相似。

这个题目作为hard 有点名不副实,理解清楚题意即可

class Solution {
    class UnionFind{
    private:
        std::vector<int> parent_; // parent[i] = k : i的父亲是k
        std::vector<int> size_;   // size[i] = k : 如果i是代表节点,size[i]才有意义( i所在的集合大小是多少),否则无意义
        std::vector<int> help_;  //  辅助结构
        int cnt_;               //一共有多少个集合

        int findRoot(int i){
            int hi = 0;
            while (i != parent_[i]){
                help_[hi++] = parent_[i];
                i = parent_[i];
            }
            for (hi--; hi >= 0; --hi) {
                parent_[help_[hi]] = i;
            }
            return i;
        }
    public:
        explicit UnionFind(int n){
            cnt_ = n;
            parent_.resize(n);
            size_.resize(n);
            help_.resize(n);
            for (int i = 0; i < n; ++i) {
                parent_[i] = i;
                size_[i] = 1;
            }
        }




        void merge(int i, int j){
            int f1 = findRoot(i);
            int f2 = findRoot(j);
            if(f1 != f2){
                if(size_[f1] >= size_[f2]){
                    parent_[f2] = f1;
                    size_[f1] = size_[f1] + size_[f2];
                }else{
                    parent_[f1] = f2;
                    size_[f2] = size_[f2] + size_[f1];
                }
                --cnt_;
            }
        }

        int counts() const{
            return cnt_;
        }

        bool isConnected(int i, int j){
            return findRoot(i) == findRoot(j);
        }
    };

public:
    int numSimilarGroups(vector<string>& strs) {
        int N = strs.size();
        UnionFind unionFind(N);
        for (int i = 0; i < N; ++i) {
            for (int j = 0; j < N; ++j) {
                // 已经连接了,不用判断相似性
                if(unionFind.isConnected(i, j)){
                    continue;
                }

                if(isSimilar(strs[i], strs[j])){
                    unionFind.merge(i, j);
                }
            }
        }

        return unionFind.counts();
    }

private:
    bool isSimilar(const string& A,const string& B){
        int cnt = 0;
        for(int i = 0; i < A.size(); i++){
            cnt += (A[i] != B[i]);
        }
        return cnt <= 2;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值