題目
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]
解題思路
剛開始的時候老是想着在掃描數組時,每掃描到一個新的數字都要確定以該數字爲開頭的一個連續序列。其實根本不需要掃到一個數字就確定一個連續序列,而是可以在掃描數組的過程中,把數字逐一地添加到未完整的連續序列中,動態地往連續序列中添加數據。整個算法過程如下:
維護兩個哈希表
frequency
和tails
.frequency
表記錄數組中每個數字出現的次數,而tails
表則記錄以某個數字結尾的連續序列的個數,比如tails[key]
的值爲2,表示以數字key
爲結尾的連續序列共有兩個。第一次掃描數組,把數組中每個數字的出現次數記錄到 frequency 表中。
第二次掃描數組,對掃描到的每一個數字
num
,如果tails[num - 1] > 0
,說明存在以num - 1
爲結尾的連續序列,則把數字num
添加到該連續序列中:tails[num - 1]--; tails[num]++
。可能有人會擔心num
可能是另一個連續序列的開始數字而不應該加入到tails[num - 1]
的連續序列中,但是任意以num
爲開始數組的連續序列都可以與tails[num - 1]
的連續序列合併:比如[1, 2, 3]
和[4, 5, 6]
兩個連續序列是可以合併成[1, 2, 3, 4, 5, 6]
這個大的連續序列的,這對於結果是沒有影響的;如果tails[num - 1] == 0
,此時我們就需要以num
爲開始數字建立一個新的連續序列。而一個連續序列至少包含 3 個數字,因此還要檢查num + 1
和num + 2
這兩個數字是否存在,如果不存在,則直接return false
,否則,新建以num + 2
數字爲結尾的連續序列。如果上述過程能進行到最後,說明所有連續序列都能夠找出來,則直接
return true
。
C++代碼實現
class Solution {
public:
bool isPossible(vector<int>& nums) {
unordered_map<int, int> frequency, tails;
for (int &num : nums) { frequency[num]++; }
for (int &num : nums) {
// 如果 frequency[num] <= 0,說明在上一輪循環中新建了
// 一個包含當前數字 num 的連續序列,直接跳過掃描下一個數字
if (frequency[num] <= 0) { continue; }
frequency[num]--;
if (tails[num - 1] > 0) {
tails[num - 1]--;
tails[num]++;
} else if (frequency[num + 1] && frequency[num + 2]) {
// 新建連續序列,要把包含進新序列的數字的出現次數也減 1
frequency[num + 1]--;
frequency[num + 2]--;
tails[num + 2]++;
} else {
return false;
}
}
return true;
}
};