[LeetCode] 846. Hand of Straights 一手順子牌


 

Alice has a hand of cards, given as an array of integers.

Now she wants to rearrange the cards into groups so that each group is size W, and consists of W consecutive cards.

Return true if and only if she can.

 

Example 1:

Input: hand = [1,2,3,6,2,3,4,7,8], W = 3
Output: true
Explanation: Alice's hand can be rearranged as [1,2,3],[2,3,4],[6,7,8]

Example 2:

Input: hand = [1,2,3,4,5], W = 4
Output: false
Explanation: Alice's hand can't be rearranged into groups of 4 

Note:

  1. 1 <= hand.length <= 10000
  2. 0 <= hand[i] <= 10^9
  3. 1 <= W <= hand.length

 

這道題說是我們在打撲克牌,是否能將手里的牌都以順子的形式出完。在打拐3挖坑或者斗地主的時候,順子牌在后期的威力是蠻大的,某些人手里憋了一把牌,結果到后期找個機會上手了之后,直接一把甩完,看的手中只有一把單牌的博主是目瞪口呆。其實到了后期,大家手中都沒啥牌了的時候,就算是很小的連牌,也不一定能要得起,而划單是最沒前途的出法,所以要盡量將手中的牌都組成順子丟出去。這里給了一個W,規定了順子的最小長度,那么我們就拿例子1來模擬下打牌吧,首先摸到了牌之后,肯定要先整牌,按從小到大的順序排列,這里就不考慮啥3最大,4最小啥的,就統一按原始數字排列吧:

1 2 2 3 3 4 6 7 8

好,下面要來組順子,既然這里是3張可連,那么從最小的開始連唄。其實這道題還是簡化了許多,真正打牌的時候,即便是3張起連,那么連4張5張都是可以的,可以這里限定了只能連W張,就使得題目變簡單了。我們用貪婪算法就可以了,首先從1開始,那么一定得有2和3,才能起連,若少了任何一個,都可以直接返回false,好那么取出這三張后,手里還有:

2 3 4 6 7 8

那么從當前手里的最小的牌2開始起連,那么手里必須要有3和4,若少了任何一個,都可以直接返回 false,好那么取出這三張后,手里還有:

6 7 8

從當前手里的最小的牌6開始起連,那么手里必須要有7和8,若少了任何一個,都可以直接返回 false,好那么取出這三張后,手里沒牌了,我們成功的連完了所有的牌。分析這個過程,不難發現,由於牌可以重復,所以要統計每張牌出現的次數,同時還要給牌按大小排序,用 TreeMap 來建立牌的大小和其出現次數之間的映射就最好不過了,利用了其可以按 key 值排序的特點。首先遍歷手中牌,建立映射。然后開始 while 循環,條件是 TreeMap 不為空,然后去除最小的那張牌,然后遍歷能組成順子的W張牌,若沒有直接返回 true,有的話,則映射值自減1,若映射值為0了,則從 TreeMap 中移除該映射對兒即可,while 循環退出后返回 true,參見代碼如下:

 

解法一:

class Solution {
public:
    bool isNStraightHand(vector<int>& hand, int W) {
        map<int, int> m;
        for (int i : hand) ++m[i];
        while (!m.empty()) {
            int start = m.begin()->first;
            for (int i = 0; i < W; ++i) {
                if (!m.count(start + i)) return false;
                if (--m[start + i] == 0) m.erase(start + i);
            }
        }
        return true;
    }
};

 

我們也可以不對 TreeMap 進行刪除操作,而是直接修改其映射值,在建立好映射對兒之后,不用 while 循環,而是遍歷所有的映射對兒,若某個映射值為0了,直接跳過。然后還是遍歷能組成順子的W張牌,若某張牌出現的次數小於順子起始位置的牌的個數,則直接返回 false,因為肯定會有起始牌剩余,無法全組成順子,這樣還避免了上面解法中一張一張減的操作,提高了運算效率。然后映射值減去起始牌的個數,最后 for 循環退出后,返回 true,參見代碼如下:

 

解法二:

class Solution {
public:
    bool isNStraightHand(vector<int>& hand, int W) {
        map<int, int> m;
        for (int i : hand) ++m[i];
        for (auto a : m) {
            if (a.second == 0) continue;
            for (int i = a.first; i < a.first + W; ++i) {
                if (m[i] < a.second) return false;
                m[i] = m[i] - a.second;
            }
        }
        return true;
    }
};

 

Github 同步地址:

https://github.com/grandyang/leetcode/issues/846

 

參考資料:

https://leetcode.com/problems/hand-of-straights/

https://leetcode.com/problems/hand-of-straights/discuss/135700/Short-Java-solution!

https://leetcode.com/problems/hand-of-straights/discuss/135598/C%2B%2BJavaPython-O(MlogM)-Complexity

 

LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM