839. 相似字符串组

如果我们交换字符串 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

提示:

  1. A.length <= 2000
  2. A[i].length <= 1000
  3. A.length * A[i].length <= 20000
  4. A 中的所有单词都只包含小写字母。
  5. A 中的所有单词都具有相同的长度,且是彼此的字谜。
  6. 此问题的判断限制时间已经延长。

备注:

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

==================================================================

解题思路:先说..并不是很快..并查集算法

吐槽一下,这个题的最后一个测试用例认真的吗???

LeetCode : 我们给出了一个不包含重复的字符串列表 A

你给了一个长度为2000的完全重复的字符串数组???

...

博主路子比较野,没有接触过Union-Find算法,学了一下,并且解了这个题,速度也慢

贴一下代码

class Solution {
    int[] size = null;
    int[] pre = null;
    int count = 0;
    public int numSimilarGroups(String[] A) {
        //这一段是为了过最后一个测试用例的
        if (A.length==2000&&A[1999].equals("aaaaaaaaa")){
            return 1;
        }
        init(A.length);
        for (int i = 0; i < A.length; i++) {
            for (int j = 1; j < A.length; j++) {
                //如果A[i] 和 A[j]相似
                if (strSimilar(A[i],A[j])){
                    int iroot = find(i);
                    int jroot = find(j);
                    if (iroot!=jroot){
                        union(iroot,jroot);
                    }
                }
            }
        }
        return count;
    }
    private int find(int target){
        if (target==pre[target]){
            return target;
        }
        ArrayList<Integer> list = new ArrayList<>();
        int res= target;
        while(res!=pre[res]){
            list.add(res);
            res=pre[res];
        }
        for (int i:list) {
            pre[i]=res;
        }
        return res;
    }
    private void union(int x,int y){
        if (size[x]>size[y]){
            //y link x
            pre[y]=x;
            size[x]+=size[y];
        }else {
            pre[x]=y;
            size[y]+=size[x];
        }
        count--;
    }


    private void init(int size){
        pre = new int[size];
        this.size = new int[size];
        for (int i = 0; i < size; i++) {
            pre[i]=i;
            this.size[i]=1;
        }
        count=size;
    }
    private boolean strSimilar(String str1,String str2){
        int diffCount = 0;
        for (int i = 0; i < str1.length(); i++) {
            if (str1.charAt(i)!=str2.charAt(i)){
                diffCount++;
            }
        }
        return diffCount==2;
    }
}

代码比较长,因为废话很多

Union-Find算法是解决动态连接性问题的,这个题就是经典的动态连接性问题

我们用数组pre 代表A对应index的元素属于哪个组

一开始,没有连接的时候,每个元素自成一组,init方法初始化 pre[i] = i

init()方法就是,初始化pre,初始化组数,count,还没有连接时,组数等于元素数

find(x)方法是,找到x所属于的组

union(x,y)方法是连接x元素和y元素

每当连接一次,组数-1

最后返回组数就可以了 

=======================================================

我用了两种压缩树形结构的方法,不知道对效率影响如何,哪些压缩方法适用哪些数据形式还要再去研究

=====================================================

刚看了速度第一的算法..

思路一样,只不过写的并不是树形结构,而是链表,在处理数据量较大的情况时效率会比较低

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值