Leetcode49. Group Anagrams

Leetcode49. Group Anagrams

Given an array of strings, group anagrams together.
Note:

  • All inputs will be in lowercase.
  • The order of your output does not matter.

Example:

Input: ["eat", "tea", "tan", "ate", "nat", "bat"],
Output:
[
  ["ate","eat","tea"],
  ["nat","tan"],
  ["bat"]
]

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

解法一 排序数组分类

思路:当且仅当它们的排序字符串相等时,两个字符串是字母异位词。
算法:维护一个映射 ans : {String -> List},其中每个键 K 是一个排序字符串,每个值是初始输入的字符串列表,排序后等于 K。在 Java 中将键存储为字符串,例如,code。 在 Python 中,我们将键存储为散列化元组,例如,(‘c’, ‘o’, ‘d’, ‘e’)

  • 时间复杂度:排序的话算作 O(Klog(K)),最外层的 for 循环,所以就是 O(NKlog(K))
  • 空间复杂度:O(NK),用来存储结果。
Python
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
    d = {
     }
    for w in strs:
        key = tuple(sorted(w))
        d[key] = d.get(key, []) + [w]
    return list(d.values())

tuple(sorted(w)):sort()无返回值,sorted()返回排序好的列表;将其转为tuple因为字典的key必须是immutable,不能是列表;tuple()会将字符串abc变为元组('a', 'b', 'c'),key是元组类型。
d[key] = d.get(key, []) + [w]d.get(key, [])取字典中键为key的值,如果值不在字典则返回[],然后将原字符串w加入字典中key对应的值。
③ 以列表的形式返回字典所有的值。
④判断是否异位的方法是将每个字符串按字母表排序后,如果相同则为异位。
⑤思路:将一组字符串的每一个元素先排序后作为字典的key,向空字典中加入元素,元素排序后的值为key,元素本来的值作为value。

class Solution(object):
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        ans = collections.defaultdict(list)#避免发生KeyError异常
        for s in strs:
            ans[tuple(sorted(s))].append(s)
        return ans.values()
Java
class Solution {
     
    public List<List<String>> groupAnagrams(String[] strs) {
     
        if (strs.length == 0) return new ArrayList();
        Map<String, List> ans = new HashMap<String, List>();
        for (String s : strs) {
     
            char[] ca = s.toCharArray();
            Arrays.sort(ca);
            String key = String.valueOf(ca);
            if (!ans.containsKey(key)) ans.put(key, new ArrayList());
            ans.get(key).add(s);
        }
        return new ArrayList(ans.values());
    }
}

解法二 按计数分类

思路:当且仅当它们的字符计数(每个字符的出现次数)相同时,两个字符串是字母异位词。

算法:我们可以将每个字符串 s 转换为字符数 count,由26个非负整数组成,表示 a,b,c 的数量等。我们使用这些计数作为哈希映射的基础。在 Java 中,我们的字符数 count 的散列化表示将是一个用 字符分隔的字符串。 例如,abbccc 将表示为 #1#2#3#0#0#0 …#0,其中总共有26个条目。 在 python 中,表示将是一个计数的元组。 例如,abbccc 将表示为 (1,2,3,0,0,…,0),其中总共有 26 个条目。

  • 时间复杂度:O(NK)
  • 空间复杂度:O(NK),用来存储结果。

Leetcode49. Group Anagrams_第1张图片

Python
class Solution:
    def groupAnagrams(strs):
        ans = collections.defaultdict(list)
        for s in strs:
            count = [0] * 26
            for c in s:
                count[ord(c) - ord('a')] += 1
            ans[tuple(count)].append(s)
        return ans.values()
Java
class Solution {
     
    public List<List<String>> groupAnagrams(String[] strs) {
     
        if (strs.length == 0) return new ArrayList();
        Map<String, List> ans = new HashMap<String, List>();
        int[] count = new int[26];
        for (String s : strs) {
     
            Arrays.fill(count, 0);
            for (char c : s.toCharArray()) count[c - 'a']++;

            StringBuilder sb = new StringBuilder("");
            for (int i = 0; i < 26; i++) {
     
                sb.append('#');
                sb.append(count[i]);
            }
            String key = sb.toString();
            if (!ans.containsKey(key)) ans.put(key, new ArrayList());
            ans.get(key).add(s);
        }
        return new ArrayList(ans.values());
    }
}

解法三 利用算术基本定理

算术基本定理,又称为正整数的唯一分解定理,即:每个大于1的自然数,要么本身就是质数,要么可以写为2个以上的质数的积,而且这些质因子按大小排列之后,写法仅有一种方式。

利用这个,我们把每个字符串都映射到一个正数上。

用一个数组存储质数 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}。

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

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

public List<List<String>> groupAnagrams(String[] strs) {
     
    HashMap<Integer, List<String>> hash = new HashMap<>();
    //每个字母对应一个质数
    int[] 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 };
    for (int i = 0; i < strs.length; i++) {
     
        int key = 1;
        //累乘得到 key
        for (int j = 0; j < strs[i].length(); j++) {
     
            key *= prime[strs[i].charAt(j) - 'a'];
        } 
        if (hash.containsKey(key)) {
     
            hash.get(key).add(strs[i]);
        } else {
     
            List<String> temp = new ArrayList<String>();
            temp.add(strs[i]);
            hash.put(key, temp);
        }

    }
    return new ArrayList<List<String>>(hash.values());
}

你可能感兴趣的:(leetcode)