1. 程式人生 > >leetcode 914. X of a Kind in a Deck of Cards

leetcode 914. X of a Kind in a Deck of Cards

題目

一摞牌,每張牌上寫了一個整數,如果能找到一個大於等於2的數X,把牌分成1或多組滿足下列條件:

  • 每組有X張牌
  • 每組裡的每張牌上寫得數字都是一樣的

Example 1:

Input: [1,2,3,4,4,3,2,1] Output: true Explanation: Possible partition [1,1],[2,2],[3,3],[4,4] Example 2:

Input: [1,1,1,2,2,2,3,3] Output: false Explanation: No possible partition. Example 3:

Input: [1] Output: false Explanation: No possible partition. Example 4:

Input: [1,1] Output: true Explanation: Possible partition [1,1] Example 5:

Input: [1,1,2,2,2,2] Output: true Explanation: Possible partition [1,1],[2,2],[2,2]

注意:

  1. 1 <= deck.length <= 10000
  2. 0 <= deck[i] < 10000

思路

把牌按照上面寫的數字分組計數(counter),將counter排序,為了找到最小的兩個計數。如果最小的計數小於2,也就是牌堆只有一張牌,則不存在大於等於2的X,返回FALSE。如果counter只有一個值,也就是隻有一種數字的牌,通過了前面的條件這張牌的張數就不小於2,至少可以按照要求分成1組,返回True。接下來是複雜一點的地方,如果counter前兩個計數的最大公約數,是後續所有計數的一個約數,那麼就返回True,否則返回False。

程式碼

class Solution:
    def hasGroupsSizeX(self, deck):
        """
        :type deck: List[int]
        :rtype: bool
        """
        def biggest_divider(a, b):
            for i in range(2, min(a, b)+1):
                if a % i == 0 and b % i == 0:
                    return i
            return False

        from collections import defaultdict
        counter = defaultdict(int)
        for i in deck:
            counter[i] += 1

        values = sorted(list(counter.values()))

        if values[0] < 2:
            return False

        if len(values) == 1:
            return True

        bd = biggest_divider(values[0], values[1])
        if not bd:
            return False
        for i in range(2, len(values)):
            if values[i] % bd !=0:
                return False
        return True

其他

討論裡面有個一行程式碼搞定的

return reduce(fractions.gcd, collections.Counter(deck).values()) > 1

很巧妙,我又學習了一下reduce,如果reduce的序列只有一個值,就返回這個值,不論reduce的函式是什麼。

這道題我試了好多次錯,沒想太明白,其中一次我的提交裡面把[1,1,1, 1,1,1, 1,1,1]判為False了,AC了,leetcode的測試用例沒覆蓋到。