版权声明:本文为博主原创文章,未经博主允许不得转载。有事联系:[email protected] https://blog.csdn.net/qq_17550379/article/details/88368763
爱丽丝有一手(hand
)由整数数组给定的牌。
现在她想把牌重新排列成组,使得每个组的大小都是 W
,且由 W
张连续的牌组成。
如果她可以完成分组就返回 true
,否则返回 false
。
示例 1:
输入:hand = [1,2,3,6,2,3,4,7,8], W = 3
输出:true
解释:爱丽丝的手牌可以被重新排列为 [1,2,3],[2,3,4],[6,7,8]。
示例 2:
输入:hand = [1,2,3,4,5], W = 4
输出:false
解释:爱丽丝的手牌无法被重新排列成几个大小为 4 的组。
提示:
1 <= hand.length <= 10000
0 <= hand[i] <= 10^9
1 <= W <= hand.length
解题思路
首先可以很容易想到暴力破解,先统计hand
中所有元素出现的数量,记录到一个字典中。然后遍历排好序的hand
,判断[i,i+W]
是不是都在字典中,如果在的话(并且字典中的值不为0
),我们就可以将字典中的对应值减一,否则的话返回False
。hand
中的元素都遍历结束后,我们返回True
。
class Solution:
def isNStraightHand(self, hand: List[int], W: int) -> bool:
n = len(hand)
if n == 0 or (n and n % W != 0):
return False
cnt = collections.Counter(hand)
hand.sort()
for i in hand:
if i in cnt:
for k in range(i, i+W):
if k not in cnt:
return False
cnt[k] -= 1
if cnt[k] == 0:
del cnt[k]
return True
要注意的是这里有一个陷阱,就是第一个元素可以有很多个,所有我们就没有采用for i in sorted(cnt)
的方式,而是通过for i in hand
并且判断i in cnt
的方式。实际上我们可以使用sorted(cnt)
的方式,不过要使用一点trick
,我们需要从后向前遍历i+w->i
,然后将遍历到的值减去cnt[i]
(而不是减1
,也就是后面元素的数量一定是要大于前面元素的)。
class Solution:
def isNStraightHand(self, hand: List[int], W: int) -> bool:
n = len(hand)
if n == 0 or (n and n % W != 0):
return False
c = collections.Counter(hand)
for i in sorted(c):
if c[i] > 0:
for j in range(W)[::-1]:
c[i + j] -= c[i]
if c[i + j] < 0:
return False
return True
我们还有一种更好的解法,但是我认为下面这种解法较难理解并且在速度上也并没有什么优势,所以我将其列出,但是不去谈它。
class Solution:
def isNStraightHand(self, hand: List[int], W: int) -> bool:
n = len(hand)
if n == 0 or (n and n % W != 0):
return False
c = collections.Counter(hand)
start = collections.deque()
last_checked, opened = -1, 0
for i in sorted(c):
if opened > c[i] or opened > 0 and i > last_checked + 1:
return False
start.append(c[i] - opened)
last_checked, opened = i, c[i]
if len(start) == W:
opened -= start.popleft()
return opened == 0
https://leetcode.com/problems/hand-of-straights/discuss/135598/C%2B%2BJavaPython-O(MlogM)-Complexity
我将该问题的其他语言版本添加到了我的GitHub Leetcode
如有问题,希望大家指出!!!