-
题目描述:
Alice 手中有一把牌,她想要重新排列这些牌,分成若干组,使每一组的牌数都是 groupSize ,并且由 groupSize 张连续的牌组成。
给你一个整数数组 hand 其中 hand[i] 是写在第 i 张牌,和一个整数 groupSize 。如果她可能重新排列这些牌,返回 true ;否则,返回 false 。 -
示例:
输入:hand = [1,2,3,6,2,3,4,7,8], groupSize = 3
输出:true
解释:Alice 手中的牌可以被重新排列为 [1,2,3],[2,3,4],[6,7,8]。
输入:hand = [1,2,3,4,5], groupSize = 4
输出:false
解释:Alice 手中的牌无法被重新排列成几个大小为 4 的组。 -
提示:
1 <= hand.length <= 104
0 <= hand[i] <= 109
1 <= groupSize <= hand.length -
解析:这道题目的难点在于如何想到考点,我们观察给定的hand,发现他是一个无序数组,本题明显对数组元素顺序有很严格的要求,所以我们首先就可以考虑对数组进行排序。然后再考虑不可能匹配成功的情况,第一种是hand的元素个数对 groupSize取余不等于0,这种很好理解,比如10个元素分成3组,无论如何也不可能做到每组元素一样;第二种是每个group不是连续的牌,这个乍一想有点麻烦,我们可以这么考虑,给了我们一个hand,元素个数为n,我们为他准备n/groupSize个箱子,首先将hand排序,然后取里面最小的元素x1作为第一个箱子的起始元素,而后对k属于[x1, x1+groupSize)每个元素进行两个操作,第一个判断k是否在hand中,如果不在,返回False,如果在,则从hand中取出,遍历完成后,说明第一个箱子满足条件,进行第二个箱子的装填,以目前hand数组的最小元素作为第二个箱子的起始元素,重复上述步骤,当遍历完成后,如果hand里面元素为空,返回True。
-
当然,我们实际操作时,不能直接对hand进行元素的删减,对应元素的查找和删除会有较高的复杂度,只要涉及到查找,我们第一反应是二分,第二嘛,就是哈希,这题就是用哈希,那么怎么用呢?我们可以记录hand中每个元素对应的个数(一个字典类型的遍历,记为cnt),然后遍历hand,,对每一个元素h,判断cnt[h]是不是等于0,如果不等于0,则以其作为七点,对k属于[h, h+groupSize)进行遍历,如果k不在cnt中,返回False,如果在,但是cnt[k]=0,返回False。遍历完成后如果cnt.values()的和为0,则返回True。但是实际上这一步,可以避免,我们创建一个变量等于hand的元素个数,记为ans,每往箱子里放一个元素,ans减去1,如果遍历完成后,ans=0,返回True,否则,返回False。解题代码如下所示:
class Solution:
def isNStraightHand(self, hand: List[int], groupSize: int) -> bool:
"""
给你一个整数数组 hand 其中 hand[i] 是写在第 i 张牌,和一个整数 groupSize 。如果她
可能重新排列这些牌,返回 true ;否则,返回 false
>>>self.isNStraightHand([1,2,3,6,2,3,4,7,8], 3)
>>>True
>>>self.isNStraightHand([1,2,3,4,5], 4)
>>>False
"""
ans = len(hand)
if ans % groupSize != 0:
return False
hand.sort()
cnt = Counter(hand)
for h in hand:
if cnt[h] == 0:
continue
else:
for i in range(groupSize):
if h+i not in cnt or cnt[h+i] == 0:
return False
cnt[h+i] -= 1
ans -= 1
return True if ans == 0 else False