Leetcode 846:一手顺子(超详细的解法!!!)

版权声明:本文为博主原创文章,未经博主允许不得转载。有事联系:[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. 1 <= hand.length <= 10000
  2. 0 <= hand[i] <= 10^9
  3. 1 <= W <= hand.length

解题思路

首先可以很容易想到暴力破解,先统计hand中所有元素出现的数量,记录到一个字典中。然后遍历排好序的hand,判断[i,i+W]是不是都在字典中,如果在的话(并且字典中的值不为0),我们就可以将字典中的对应值减一,否则的话返回Falsehand中的元素都遍历结束后,我们返回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

如有问题,希望大家指出!!!

猜你喜欢

转载自blog.csdn.net/qq_17550379/article/details/88368763