题目:
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:
思路:
感觉这道题目的难度直逼hard。我参考了网上的解法:
1)如果中间存在不连续的数字,则我们将它们分开,分别检查每个连续的序列,例如1,2,3,4,5,9,10,11。
2)计算每个数字出现的次数counts(每个数字的具体值其实并不重要)。
3)定义ones[i]表示长度为1的以第i个数字结尾的子串的个数;twos表示长度为2的以第i个数字为结尾的子串个数,tol表示所有以第i个数字作为结尾的子串个数。当处理下一个数字的时候,如果counts[i + 1] < ones + twos,那么说明没有办法进行合法的split了,所以返回false。否则我们就优先将当前的数字连接到相对短的子串上。所以:
twos[i + 1] = ones[i],ones[i +1] = counts[i + 1] - tot[i],而tot[i + 1] = counts[i + 1]。
最终整个子串能够被合法分解的充要条件是ones[n]和twos[n]都是0。看上面的递推公式可以发现,ones,twos和tot的第i + 1个值只与它们的第i和第i+1个值有关,所以该DP的空间复杂度可以进一步降低到O(1),请见下面的代码片段。
代码:
class Solution {
public:
bool isPossible(vector& nums) {
int n = nums.size(), k = 0;
for (int i = 1; i < n; i++) {
if (nums[i] - nums[i - 1] > 1) { // not continous, so check separately
if (!check(nums, k, i)) {
return false;
}
k = i;
}
}
return check(nums, k, n);
}
private:
bool check(vector& nums, int s, int e) {
int ones = 0, twos = 0, tot = 0;
for (int i = s + 1, cnt = 1; i <= e; i++) {
if (i < e && nums[i] == nums[i-1]) {
cnt++;
}
else {
if (cnt < ones + twos) {
return false;
}
twos = ones;
ones = max(0, cnt - tot);
tot = cnt;
cnt = 1;
}
}
return ones == 0 && twos == 0;
}
};