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

 

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

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

Return true if and only if she can.github

 

Example 1:算法

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

Example 2:spa

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

Note:code

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

 

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

1 2 2 3 3 4 6 7 8blog

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

2 3 4 6 7 8leetcode

那麼從當前手裏的最小的牌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 題目講解彙總(持續更新中...)

相關文章
相關標籤/搜索