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

17 篇文章 0 订阅
14 篇文章 0 订阅

题目

一摞牌,每张牌上写了一个整数,如果能找到一个大于等于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的函数是什么。不过我这个方法更快,击败了99%多的提交。

这道题我试了好多次错,没想太明白,其中一次我的提交里面把[1,1,1, 1,1,1, 1,1,1]判为False了,AC了,leetcode的测试用例没覆盖到。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值