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 <= hand.length <= 10000
0 <= hand[i] <= 10^9
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