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]
思路 1:使用两个哈希表,这里是贪心的思想:如果当前的数可以放在之前的序列之后,就放,若果不行,就形成一个新的序列。下面的代码的思路是:通过设置一个chance数组,提供这样的后续延续机会,因为数组是排过序的,遇到重复的数首先是构成新的数列。
class Solution {
public:
bool isPossible(vector<int>& nums) {
//这个题就是模拟取数的过程
//在取数的时候,刚开始的时候取三个数,遇到新的数加在之前形成的数之后;遇到重复的数,重新行程一个三数组合。
//下面使用两个哈希表,一个统计所有数出现的次数,另外一个是取数的时候做统计。
//关键是另外一个哈希表的意义:表示当前数的潜在填补可能数,比如chance[i]==2,说明i这个数在之前有两个已经形成的序列后可以放进去。
//每当一个数用上了,就在freq中减掉,如果潜在位置数也用了一个,也减1
//在下面的代码中进行详细的说明
//问题的核心是:对于已经形成的序列,后面都有一个位置可以再添加一个数,我们成他为一个机会。就是说如果这个机会对应的数如果不能用于组成另外一个序列,他还可以有这个机会添加到已经构成的序列后面。因为是排过序的,如果没有重复的数,当前的序列会不断扩充。
//遇到了重复的数,当前的已知序列没有能提供这个机会添加到后面,那么这个数要行程一个长度为3的新序列,同时也增加一个尾添加机会
unordered_map<int,int> freq;//统计所有数的出现次数
unordered_map<int,int> chance;
for(int i=0;i<nums.size();i++)
freq[nums[i]]++;
for(auto i:nums)
{
if(freq[i]==0) continue;//当前数已经用完
if(chance[i]>0)//有序列可以有位置包养当前的数,就使用一个位置
{
chance[i]--;//这个位置少了一个机会
chance[i+1]++;//下一个位置多了一个容纳下一个数的位置
}
else if(freq[i+1]>0&&freq[i+2]>0)//现在没有序列可以容纳当前的元素,说明出现了重复的值,或者是中间断裂。因此需要形成一个新的序列
{
freq[i+1]--;
freq[i+2]--;
chance[i+3]++;
}
else return false;
freq[i]--;
}
return true;
}
};
思路2:
这种思路类似。通过设置一个哈希表,键是当前序列的最后一个数,值是一个最小堆,意思是构成一个以这个数结尾的对应的所有序列,序列长度最小的那个排在堆顶。对于一个新的数,首先寻找他能不能在放到别的序列后面,而且是找长度小的那个放,放了之后,将这个堆顶弹出,在当前数结尾的堆中加入新的长度值。如果找不到现有序列去放这个数,就要开辟一个新的序列结尾。同时设置一个 变量。每当形成一个新的序列,need_more加1,当这个序列达到3时,need_more减一。
因为长度大于3序列已经满足要求了,长度小于3的序列需要首先满足。
如果最终need_more 不等于0,说明有的序列没有达到三个
class Solution {
public:
bool isPossible(vector<int>& nums)
{
unordered_map<int, priority_queue<int, vector<int>, std::greater<int>>> backs;
// Keep track of the number of sequences with size < 3
int need_more = 0;
for (int num : nums)
{
if (! backs[num - 1].empty())
{ // There exists a sequence that ends in num-1
// Append 'num' to this sequence
// Remove the existing sequence
// Add a new sequence ending in 'num' with size incremented by 1
int count = backs[num - 1].top();
backs[num - 1].pop();
backs[num].push(++count);
if (count == 3)
need_more--;
}
else
{ // There is no sequence that ends in num-1
// Create a new sequence with size 1 that ends with 'num'
backs[num].push(1);
need_more++;
}
}
return need_more == 0;
}
};