1. 程式人生 > >Leetcode演算法——49、字串分組(group anagrams)

Leetcode演算法——49、字串分組(group anagrams)

給定一個字串陣列,將所有字串分組,每一組的字串包含的字元相同但是順序不同。

示例:

輸入: ["eat", "tea", "tan", "ate", "nat", "bat"],
輸出:
[
 ["ate","eat","tea"],
 ["nat","tan"],
 ["bat"]
]

思路

本文提出了 3 種解法,可以抽象出一個共同的思路:

都是定義了一種對映,將字串對映到一個key,並保證同一組字串對映到相同的key,不同組字串對映到不同的key。

1、排序法

對每個字串,先排序,然後作為 key,將原字串加入到 key 對應的 value 中。

這樣,不同字元順序的字串排序後 key 都相等,因此一個 key 對應的 value 自成一組。

示例:

‘aab’ -> ‘aab’
‘aba’ -> ‘aab’
key 相等,因此分到一組。

排序的演算法複雜度為 O(nlogn),因此整體演算法複雜度為 O(mnlogn)。

m為字串個數,n為每個字串的平均長度。

2、計數法

對每個字串,對包含的字元的種類和個數進行統計,然後將同樣記錄結果的字串聚集在一起。

可以用一個 26 位的字串作為 key,代表 26 個字母的個數。

示例:

‘aab’ -> ‘21000000000000000000000000’
‘aba’ -> ‘21000000000000000000000000’
key 相等,因此分到一組。

相當於也是用了排序法,只不過是桶排序,演算法複雜度為O(n),因此整體演算法複雜度為O(mn)。

3、累乘法

將字串中每個字元對應素數的累乘,將結果作為 key。

26 個字母對應的素數可以是任意的,只要互不相同即可,如:
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101]

示例:

‘aab’ -> 223=12
‘aba’ -> 232=12
key 相等,因此分到一組。

缺點:乘積結果與字串長度成指數增長,容易資料溢位。

整體演算法複雜度為O(mn)。

python實現

def groupAnagrams(strs):
    """
    :type strs: List[str]
    :rtype: List[List[str]]
    排序法。
    """
    dic = dict()
    for s in strs:
        key = str(sorted(s))
        dic[key] = dic.get(key, []) + [s]
    return list(dic.values())

def groupAnagrams2(strs):
    """
    :type strs: List[str]
    :rtype: List[List[str]]
    計數法。
    """
    dic = dict()
    for s in strs:
        l = [0] * 26 # 26個字母的計數
        for char in s:
            l[ord(char) - ord('a')] += 1
        key = str(l)
        dic[key] = dic.get(key, []) + [s]
    return list(dic.values())

from functools import reduce 
def groupAnagrams3(strs):
    """
    :type strs: List[str]
    :rtype: List[List[str]]
    累乘法。
    """
    prime_list = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101]
    dic = dict()
    for s in strs:
        if s:
            char_to_primes = [prime_list[ord(char) - ord('a')] for char in s]
            key = reduce(lambda x,y : x*y, char_to_primes)
        else:
            key = 0
        dic[key] = dic.get(key, []) + [s]
    return list(dic.values())

if '__main__' == __name__:
    strs = ["eat", "tea", "tan", "ate", "nat", "bat"]
    print(groupAnagrams3(strs))