题目
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;
}
};