LeetCode 49 字母异位词分组

题目

给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。

示例:

输入: ["eat", "tea", "tan", "ate", "nat", "bat"]
输出:
[
  ["ate","eat","tea"],
  ["nat","tan"],
  ["bat"]
]
说明:

所有输入均为小写字母。
不考虑答案输出的顺序。

思路一

  • 创建一个boolean数组,长度为给定数组的长度。用来记录数组中字符串是否已经加入了其他异位词类型中
  • 遍历整个给定数组,如果这个字符串没有加入其他类型,将它加入到新创建到的数组中,并且从当前开始,与之后的字符串比较,是否为同一异位词, 是的话也加入这个数组中,并且将这个字符串boolean标记为true。
  • 写 比较字符串是否为异位词 方法

代码

class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        List<List<String>> list = new ArrayList<>();
        boolean[] judge = new boolean[strs.length];
        for (int i = 0; i < strs.length; i++) {
            if(!judge[i]) {   //字符串不是其他类型的,没加入其他类型异位词
                List<String> temp = new ArrayList<>();
                temp.add(strs[i]);
                for (int j = i+1; j < strs.length; j++) {
                    if(judge[j] == false && equals(strs[i] , strs[j])) {
                        temp.add(strs[j]);
                        judge[j] = true;
                    }
                }
                list.add(temp);
            }  
        }
        return list;
    }
    public boolean equals(String s, String t) {  //自己建立的类似哈希表,因为只有26个字母并且小写
        if (s.length() != t.length()) {
            return false;
        }
        int[] a = new int[26];
        for(int i = 0; i < s.length(); i++) {
            a[s.charAt(i) - 'a']++;
            a[t.charAt(i) - 'a']--;
        }
        for (int count : a) {
            if(count != 0) {
                return false;
            }
        }
        return true;
    }

private boolean equals(String string1, String string2) {  //这里是用纯hash表,将字符放入hash表中,什么字符都行
    Map<Character, Integer> hash = new HashMap<>();
    //记录第一个字符串每个字符出现的次数,进行累加
    for (int i = 0; i < string1.length(); i++) {
        if (hash.containsKey(string1.charAt(i))) {
            hash.put(string1.charAt(i), hash.get(string1.charAt(i)) + 1);
        } else {
            hash.put(string1.charAt(i), 1);
        }
    }
     //记录第一个字符串每个字符出现的次数,将之前的每次减 1
    for (int i = 0; i < string2.length(); i++) {
        if (hash.containsKey(string2.charAt(i))) {
            hash.put(string2.charAt(i), hash.get(string2.charAt(i)) - 1);
        } else {
            return false;
        }
    }
    //判断每个字符的次数是不是 0 ,不是的话直接返回 false
    Set<Character> set = hash.keySet();  //返回一个集合是key的Set
    for (char c : set) {
        if (hash.get(c) != 0) {
            return false;
        }
    }
    return true;
}



    
}

复杂度分析

时间复杂度:虽然有俩个for循环,但是通过boolean数组标记,每个值都只访问了一遍,所以复杂度为O(N),下面比较函数,O(K),K是字符串长度。 所以,总的时间复杂度O(N*K)
空间复杂度:O(N*K)

思路二

把一类的字符串用某一种方法唯一的映射到同一个位置就可以。 使用hash表。
确认好key和value
key是一种类型的字符串,将字符串中字符排好序,确认好这一类型
value是链表,属于这一类型的字符串都加入
结果直接 new ArrayList<List>(hash.values());

代码

class Solution {
     public List<List<String>> groupAnagrams(String[] strs) {
         HashMap<String, List<String>> hash = new HashMap<>();
         for (int i = 0; i < strs.length; i++) {
             char[] a = strs[i].toCharArray();  //每个字符串变成数组
             Arrays.sort(a);                    //排好序
             String key = String.valueOf(a);    //映射成key
             if (hash.containsKey(key)) {       //如果hash里有这种类型,字符串加入这个链表
                 hash.get(key).add(strs[i]);
             } else {                           //如果hash表没有这中类型,new一个链表,并加入
                 List<String> list = new ArrayList<>();
                 list.add(strs[i]);
                 hash.put(key, list);
             }
         }
         return new ArrayList<List<String>>(hash.values()); 
    }
}

复杂度分析

时间复杂度:排序的话算作 O(NlogN),最外层的 for 循环,所以就是 O(K*N logN),字符串长度N,给定数组中长度为K,里面有K个字符串。
空间复杂度:O(N*K)

优化

如何去优化,去选择正确的key,去存储对应的value。思路一中是暴力,每个字符串都需要相互比较一下是不是属于同一类型。
解法二中是,通过key来建立类型,放入hash表中。每个字符串都看看自己的类型是不是已经有的还是没有的。
这里的类型是 直接字符串排序看是否相同,其中排序需要耗费时间NloghN。 如何优化呢?
可以设计一种不需要如此时间复杂度的类型,与字符串匹配。每个字符串查看自己类型的时候更快。

优化

  • 用一个数组存储质数 prime = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103}。26个

  • 然后每个字符串的字符减去 ’ a ’ ,然后取到 prime 中对应的质数。把它们累乘。

  • 例如 abc ,就对应 ‘a’ - ‘a’, ‘b’ - ‘a’, ‘c’ - ‘a’,即 0, 1, 2,也就是对应素数 2 3 5,然后相乘 2 * 3 * 5 = 30,就把 “abc” 映射到了 30。

  • 这样,这个30是唯一的,只能由‘a’,‘b’,‘c’三个字符才能得到,这就符合题目,属于同一类类型
    时间复杂度:O(n∗K),K 是字符串的最长长度。
    空间复杂度:O(N*K),用来存储结果。

作者:windliang
来源:力扣(LeetCode)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值