题目
一摞牌,每张牌上写了一个整数,如果能找到一个大于等于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 <= deck.length <= 10000
- 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的测试用例没覆盖到。