Description

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:

  1. The length of the input is in range of [1, 10000]

分析

题目的意思是:把一个数组分割成多个连续子序列,每个子序列的长度至少为3.

  • 使用两个哈希表map,第一个map用来建立数字和其出现次数之间的映射freq,第二个用来建立可以加在某个连续子序列后的数字及其可以出现的次数之间的映射need。
  • 对于第二个map,例如有个子序列[1,2,3],那么后面可以加上4,所以就建立4的映射。
  • 首先遍历一遍数组,统计每个数字出现的频率,然后开始遍历数组,对于每个遍历到的数字,首先看其当前出现的次数,如果为0,则继续循环;
  • 如果need中存在这个数字的非0映射,那么表示当前的数字可以加到某个序列的末尾,将当前数字的映射值自减1,然后将下一个连续数字的映射值加1,因为当[1,2,3]连上4后变成[1,2,3,4]之后,就可以连上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;
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;
}
};

参考文献

​[LeetCode] Split Array into Consecutive Subsequences 将数组分割成连续子序列​