類別:greedy
難度:medium
題目描述
首先,需要正確理解題目的意思,最開始的時候誤解爲是隻要將所有的數字分成兩組,然後每一組中的數字含有三個以上連續的數字,後來發現並不是。
題目的意思是:將數組劃分爲子數組,使得每個子數組中的數字都是連續無重複的並且每個子數組的長度需要大於等於三。判斷是否能夠進行這樣的劃分,可以的話返回true,否則返回false。
算法分析
在前面數字劃分的基礎上進行後面數字的劃分。
需要保證數組劃分以後不存在長度爲1或者是長度爲2的子數組。
每次對於一個新的遍歷到的數字,優先劃分給長度爲2的數字。
舉個例子:
1,2,3,4,4,5
首先是計算每一個數字(1,2,3,4,5)的數目,分別爲:1,1,1,2,1
對1,2,3,4,5這些數字進行遍歷:
- 到達1,以1結尾的長度爲1的子數組的數目是1、以1結尾的長度爲2的子數組的數目是0、以1結尾的總的子數組的數目的1 【1】
- 到達2,(2添加到第一步中長度爲1的子數組中),以2結尾的長度爲1的子數組的數目是0、以2結尾的長度爲2的子數組的數目是1、以2結尾的總的子數組的數目的1 【1,2】
- 到達3,(3添加到第二步中長度爲2的子數組中),以3結尾的長度爲1的子數組的數目是0、以3結尾的長度爲2的子數組的數目是1、以3結尾的總的子數組的數目的1 【1,2,3】
- 到達4,有兩個4,這個時候,以4結尾的長度爲1的子數組的數目是1、以4結尾的長度爲2的子數組的數目是0、以3結尾的總的子數組的數目的2,【1,2,3,4】,【4】
- 到達5,【1,2,3,4】,【4,5】
- 可以得出規律,長度爲1的以x結尾的子數組的數目爲(x的數目-上一步中總的子數組的數目)
- 長度爲2的以x結尾的子數組的數目爲(上一步中以x-1結尾的子數組的數目)
- 總的以x結尾的子數組的數目爲數字x的數目
因爲最後到達第五步的時候已經結束了,但是還存在長度爲2的分組,所以這個數組無法按要求進行劃分。
代碼實現:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// 把數組分成連貫的子數組(相鄰兩個數字之間相差1,並且不能夠包含重複的數字)
// 並且子數組的長度必須大於等於3
bool check(vector<int>& nums, int begin, int end) {
int n = nums[end]-nums[begin]+1;
vector<int> count(n, 0);
int temp = nums[begin];
// 計算每個數字出現的次數
for (int i = begin; i <= end; ++i) {
count[nums[i] - temp]++;
}
vector<int> ones(n+1, 0), twos(n+1, 0), total(n+1,0);
for (int i = 0; i < n; ++i) {
if (count[i] < ones[i] + twos[i]) return false;
twos[i+1]=ones[i];
ones[i+1]=max(0, count[i]-total[i]);
total[i+1]=count[i];
}
return (ones[n] == 0) && (twos[n] == 0);
}
bool isPossible(vector<int>& nums) {
int n = nums.size();
int begin = 0;
for (int i = 1; i < n; ++i) {
if (nums[i] - nums[i - 1] > 1) {
if (!check(nums, begin, i-1)) {
return false;
}
begin = i;
}
}
return check(nums, begin, n - 1);
}
int main() {
int num, n;
cin >> n;
vector<int> nums;
for (int i = 0; i < n; ++i) {
cin >> num;
nums.push_back(num);
}
cout << isPossible(nums) << endl;
return 0;
}