You are given an integer array sorted in ascending order (may contain duplicates), you need to split them into several subsequences, where each subsequences consist of at least 3 consecutive integers. Return whether you can make such a split.
Example 1:
Input: [1,2,3,3,4,5] Output: True Explanation: You can split them into two consecutive subsequences : 1, 2, 3 3, 4, 5
Example 2:
Input: [1,2,3,3,4,4,5,5] Output: True Explanation: You can split them into two consecutive subsequences : 1, 2, 3, 4, 5 3, 4, 5
Example 3:
Input: [1,2,3,4,4,5] Output: False
Note:
- The length of the input is in range of [1, 10000]
博主第一眼看到這題,心想,我去,這不就是打牌么,什么挖坑,拐3,紅桃4啊,3個起連,有時候排組合的好,就不用划單兒。這道題讓將數組分割成多個連續遞增的子序列,注意這里可能會產生歧義,實際上應該是分割成一個或多個連續遞增的子序列,因為 [1,2,3,4,5] 也是正確的解。這道題就用貪婪解法就可以了,使用兩個 HashMap,第一個 HashMap 用來建立數字和其出現次數之間的映射 freq,第二個用來建立可以加在某個連續子序列后的數字與其可以出現的次數之間的映射 need。對於第二個 HashMap,舉個例子來說,就是假如有個連牌,比如對於數字1,此時檢測數字2和3是否存在,若存在的話,表明有連牌 [1,2,3] 存在,由於后面可以加上4,組成更長的連牌,所以不管此時牌里有沒有4,都可以建立 4->1 的映射,表明此時需要一個4。這樣首先遍歷一遍數組,統計每個數字出現的頻率,然后開始遍歷數組,對於每個遍歷到的數字,首先看其當前出現的次數,如果為0,則繼續循環;如果 need 中存在這個數字的非0映射,那么表示當前的數字可以加到某個連的末尾,將當前數字在 need 中的映射值自減1,然后將下一個連續數字的映射值加1,因為當 [1,2,3] 連上4后變成 [1,2,3,4] 之后,就可以連上5了,說明此時還需要一個5;如果不能連到其他子序列后面,則來看其是否可以成為新的子序列的起點,可以通過看后面兩個數字的映射值是否大於0,都大於0的話,說明可以組成3連兒,於是將后面兩個數字的映射值都自減1,還有由於組成了3連兒,在 need 中將末尾的下一位數字的映射值自增1;如果上面情況都不滿足,說明該數字是單牌,只能划單兒,直接返回 false。最后別忘了將當前數字的 freq 映射值自減1。退出 for 循環后返回 true,參見代碼如下:
class Solution { public: bool isPossible(vector<int>& nums) { unordered_map<int, int> freq, need; for (int num : nums) ++freq[num]; for (int num : nums) { if (freq[num] == 0) continue; if (need[num] > 0) { --need[num]; ++need[num + 1]; } else if (freq[num + 1] > 0 && freq[num + 2] > 0) { --freq[num + 1]; --freq[num + 2]; ++need[num + 3]; } else return false; --freq[num]; } return true; } };
Github 同步地址:
https://github.com/grandyang/leetcode/issues/659
類似題目:
參考資料:
https://leetcode.com/problems/split-array-into-consecutive-subsequences/