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]
分析
这一题目还是挺新颖的,我第一时间也没有想到能够在时间复杂度内的解法。
先说一下最初想到的解法,我们使用二维数组记录所有的subsequences。遍历nums,每一个数nums[i]都在二维数组中寻找可以append的最短的数组,如果找不到,就以这个数为开头新增一个数组。
例如:1,2,3,3,4,5
[1]->[1,2]->[1,2,3]->[1,2,3] -> [1,2,3] -> [1,2,3]
[3] [3,4] [3,4,5]
这种解法会超时,因为每次我们都需要寻找最短的可用数组,最差条件下可能会有O(n*n)的复杂度,所以会超时。
在网上看到了其他人的解法,其实我们不必使用二维数组记录所有的subsquence,只需要使用map记录每一个subsquence最后一位数,即可。但是在每一次新起一个开头时,例如上个例子中的nums[4],都需要直接判断之后是否有nums[4] + 1, nums[4] + 2存在。如果存在就直接将这三个数字组成一个新的数组。
Code
超时的解法
class Solution {
public:
bool isPossible(vector<int>& nums) {
vector<vector<int>> subs;
int length = nums.size();
if (length < 3)
return false;
subs.push_back(vector<int>(1, nums[0]));
for (int i = 1; i < length; i ++)
{
int minLen = INT_MAX;
int index = -1;
for (int j = 0; j < subs.size(); j ++)
{
if (nums[i] == subs[j].back() + 1)
{
if (subs[j].size() < minLen)
{
index = j;
minLen = subs[j].size();
}
}
}
if (index == -1)
{
subs.push_back(vector<int>(1, nums[i]));
continue;
}
else
{
subs[index].push_back(nums[i]);
}
}
for (int i = 0; i < subs.size(); i ++)
{
if (subs[i].size() < 3)
return false;
}
return true;
}
};
Accept解法
class Solution {
public:
bool isPossible(vector<int>& nums) {
map<int, int> freq;
map<int, int> q;
int length = nums.size();
for (int i = 0; i < length; i ++)
{
if (freq.find(nums[i]) == freq.end())
freq[nums[i]] = 1;
else
freq[nums[i]] ++;
}
for (int i = 0; i < nums.size(); i ++)
{
int current = nums[i];
if (freq[current] == 0)
{
continue;
}
if (q.find(current) == q.end() || q[current] == 0)
{
if (freq.find(current + 1) == freq.end() ||
freq.find(current + 2) == freq.end() ||
freq[current + 1] == 0 ||
freq[current + 2] == 0)
{
return false;
}
if (q.find(current + 3) == q.end())
q.insert(make_pair(current + 3, 1));
else
q[current + 3] ++;
freq[current] --;
freq[current + 1] --;
freq[current + 2] --;
}
else
{
freq[current] --;
q[current] --;
if (q.find(current + 1) == q.end())
q[current + 1] = 1;
else
q[current + 1] ++;
}
}
return true;
}
};
运行效率
Runtime: 188 ms, faster than 20.00% of C++ online submissions for Split Array into Consecutive Subsequences.
Memory Usage: 18.1 MB, less than 93.55% of C++ online submissions forSplit Array into Consecutive Subsequences.