输入一个按升序排序的整数数组(可能包含重复数字),你需要将它们分割成几个子序列,其中每个子序列至少包含三个连续整数。返回你是否能做出这样的分割?
示例 1:
输入: [1,2,3,3,4,5] 输出: True 解释: 你可以分割出这样两个连续子序列 : 1, 2, 3 3, 4, 5
示例 2:
输入: [1,2,3,3,4,4,5,5] 输出: True 解释: 你可以分割出这样两个连续子序列 : 1, 2, 3, 4, 5 3, 4, 5
示例 3:
输入: [1,2,3,4,4,5] 输出: False
提示:
思路:这道题是通过维护两个map来做的,第一个freq是对应数字出现的次数,第二个need是对应数字待拼接的次数(举例子如果数组是[1,2,3,3,4,4,5,5] ,那么当遍历到1时,发现其后两个数字2,3可以和1组成数列,那么4就可以拼接到[1,2,3]这个数列后面,所以need[4]++,那么当遍历到4时,发现他可以拼接到已有的数列中,这里大家有问题了,为什么4不能作为一个新的数列的开头呢?这个问题后面会说)。那么我们的做法就是先统计每个数字出现的次数。然后在第二次循环的时候,先判断当前数字次数是否为0,如果为0就跳过(为0证明当前数字已经被前面的数字承包了,比如[1,2,3,3],当遍历到1时,2,3的次数都被减1了,2的次数变成0,3的次数变成1,那么当遍历到2的时候就直接跳过,遍历到3的时候才不跳过急需处理),否则判断当前数字的need是否大于0,如果大于0就把当前数字的need减1,(当前数字+1)对应的数字的need+1(need表示当前的数字可以被拼接到已有数列后面的次数),如果上面两种情况都不满足(当前数字既没有被前面的数字承包(freq等于0),也不能拼接到任何一个数列后面),那么只能作为一个新数列的开头了,并且会越级的先承包后面两个数字并且把后面第三个数字的need可拼接次数+1。
参考代码:
class Solution {
public:
bool isPossible(vector& nums) {
unordered_map freq, need;
for (auto num : nums) freq[num]++;
for (auto num : nums) {
if (!freq[num]) continue;
else 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;
}
};