Leetcode.839. 相似字符串组---并查集思想

本文介绍了一种利用并查集解决字符串相似组问题的方法,通过转换矩阵和优化思维,避免了复杂的字符串比较。讲解了如何将字符串数组转换为关系矩阵,并展示了两种简化实现的代码片段。核心在于利用字符串下标作为标识,降低时间复杂度,快速找出相似字符串组的数量。
摘要由CSDN通过智能技术生成

839. 相似字符串组

如果交换字符串 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),一种把某个字符串的字母的位置(顺序)加以改换所形成的新词。

题解:

方法一:并查集(转换矩阵)

此题明显是一个并查集问题,关于并查集的问题我们可以通过这一博客进行加深了解并查集—省份数量。确认为并查集后,我们可以直接套用并查集模板,即使这是一道困难题其实在你掌握了并查集的思想后也是极其简单的。

  • 为了能够更好理解,我们可以先将字符串数组strs转换为矩阵,就像省份数量一题一样,我们先得到一个表示各个字符串之间是否存在连接关系的矩阵matrix,接着初始化并查集,遍历存储连接关系的矩阵matrix,即可将题目给定的strs字符串数组变成一个已经具有连接关系的并查集。最后的操作自然是遍历该并查集,查找其有几个部分即可。

代码:

class Solution {
    public int numSimilarGroups(String[] strs) {
        int[] par = new int[strs.length];
        for(int i=0;i<par.length;i++){
            par[i] = i;    //先让每个字符串各自为一个集体
        }

        int res = 0;
        int[][] matrix = new int[strs.length][strs.length];
        check(matrix,strs);   //将字符串数组转换为整型数组,即转换为关系矩阵

		//遍历关系矩阵
        for(int i=0;i<matrix.length;i++){
            for(int j=0;j<matrix[0].length;j++){
                if(matrix[i][j]==1){ //为1则代表i,j代表的字符串之间有连接关系
                    union(i,j,par);  //并查集内部对该两个模块进行连接
                }
            }
        }

        for(int i=0;i<par.length;i++){  //遍历并查集
            if(par[i]==i){    //并查集内部有好几个群体,我们只要知道群体的种类数量即可
                res++;		  //这里就是通过只看每个群体的老大,看共有几个老大来判断有几个群体
            }
        }

        return res;
    }

	//将字符串数组转换为关系矩阵
    public void check(int[][] matrix,String[] strs){
        for(int i=0;i<strs.length;i++){
            for(int j=0;j<strs.length;j++){
                if(checkcheck(strs[i],strs[j])){
                    matrix[i][j] = 1;
                }
            }
        }
    }
	
	//检查两个字符串之间是否具有连接关系,即这两个字符串是否为相似字符串
    public boolean checkcheck(String s1,String s2){
        int dif = 0;
        for(int i=0;i<s1.length();i++){
            if(s1.charAt(i)!=s2.charAt(i)){
                dif++;
            }
        }

        if(dif==0 || dif==2){
            return true;
        }

        return false;
    }

	//并查集union函数
    public void union(int x,int y,int[] par){
        int tx = find(x,par);
        int ty = find(y,par);
        if(tx!=ty){
            par[tx] = par[ty];
        }
    }
	
	//并查集find函数
    public int find(int x,int[] par){
        while(par[x]!=x){
            x = par[x];
        }

        return x;
    }
}

在这里插入图片描述

方法二:并查集优化(思维转换)

  • 通过进一步思考我们发现不用将字符串数组转换为关系矩阵,因为字符串数组的下标完全可以当成我们的标识,即字符串数组的下标可以直接当成关系矩阵matrix[i][j]的i和j,因此我们可以直接对字符串数组当成关系矩阵进行操作,这里checkcheck(strs[i],strs[j]) 就相当于前面判断matrix[i][j]==1的操作。
  • 并且由于这里在checkcheck()函数代码层面,我们使用了三层for循环,因此时间复杂度巨大,所以我们在checkcheck函数中能多省几次遍历就多省几次,这样在套上外层的两层for后就会快好多。

代码:

class Solution {
    public int numSimilarGroups(String[] strs) {
        int[] par = new int[strs.length];
        for(int i=0;i<par.length;i++){
            par[i] = i;
        }

        int res = 0;

        for(int i=0;i<strs.length;i++){
            for(int j=0;j<strs.length;j++){
                if(checkcheck(strs[i],strs[j])){
                    union(i,j,par);
                }
            }
        }

        for(int i=0;i<par.length;i++){
            if(par[i]==i){
                res++;
            }
        }

        return res;
    }

    public boolean checkcheck(String s1,String s2){
        int dif = 0;
        for(int i=0;i<s1.length();i++){
            if(s1.charAt(i)!=s2.charAt(i)){
                dif++;
            }
            if(dif>2){
                return false;
            }
        }
        return true;
    }

    public void union(int x,int y,int[] par){
        int tx = find(x,par);
        int ty = find(y,par);
        if(tx!=ty){
            par[tx] = par[ty];
        }
    }

    public int find(int x,int[] par){
        while(par[x]!=x){
            x = par[x];
        }

        return x;
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

向光.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值