Leetcode659。配列を連続したサブシーケンスに分割します
質問の語幹
昇順でソートされた整数num(繰り返し数を含む場合があります)の配列を指定します。各サブシーケンスが連続する整数で構成され、長さが3以上の1つ以上のサブシーケンスに分割してください。
上記のセグメンテーションを完了できる場合はtrueを返し、そうでない場合はfalseを返します。
例1:
入力:[1,2,3,3,4,5]
出力:True
説明:
2つの連続するサブシーケンスをセグメント化できます:
1、2、3
3、4、5
実施例2:
入力:[1,2,3,3,4,4,5,5]
出力:真の
説明:
ことはできセグメント二つの連続するサブ:
1、2、3、4、5
3、4、5
例3:
入力:[1,2,3,4,4,5]
出力:False
ヒント:
入力配列の長さは[1、10000]です。
回答
直観的には理解できたものの、合格できなかった初版は、高さの始点を更新する際に適切に処理されませんでした。
写真を見てください。
class Solution {
public:
bool isPossible(vector<int>& nums) {
int n = nums.size();
if(n <= 2){
return false;
}
vector<int> pileHeight(n);
int prePileValue = 1,currentPileValue = 0;
int samePileCount = 1;
int pileCount = 0;
pileHeight[1] = 0;
for(int i = 1 ; i < n ; ++i){
if(nums[i] != nums[i-1]){
pileHeight[1] = i;
}
//出现了前一个数不同的数
if(nums[i] != nums[i-1]){
//结算上一个堆的大小,堆数+1
pileCount++;
//高度上升,记录起点
if(currentPileValue > prePileValue){
for(int j = prePileValue ; j <= currentPileValue ; ++j){
pileHeight[currentPileValue] = pileCount;
}
}else if(currentPileValue < prePileValue){
//高度下降,获得等高宽度
//处理峰顶的情况
if(samePileCount < 3){
return false;
}
if(pileCount - pileHeight[currentPileValue] + 1 < 3){
return false;
}
currentPileValue = 1;
}else{
//高度相等
samePileCount++;
currentPileValue = 1;
}
}else{
currentPileValue++;
}
}
//处理弹出循环的情况,即最后一个堆没有结算的情况。此时又有
if(currentPileValue > prePileValue){
return false;
}else{
if(n - pileHeight[currentPileValue] < 3){
return false;
}else{
return true;
}
}
}
};
/*
猜测算法:
一个连续子序列在重复数字第一次减少时终止,比如:
1 2 3 3 4 4 5 6
即分为1 2 3 4 和 4 5 6
1 2 3 3 3 4 4 4 5 5 6 6 7
分为 1 2 3 4、3 4 5 6、3 4 5 6 7
(第一个1234分出来后34的重复次数减小为2了,所以跟67相同)
1 2 3 3 4 5
1 1 2 2 3 3 4
归纳出更为简单的规律:记某个数字重复出现的次数为X,则对于每个数字,有数列Xn。对于Xn,对于任意连续的若干项,若相同值的项数存在<3的情况则无法分割。
记某个数字重复出现的次数为X,则对于每个数字有数列Xn,将数列图像化为直方图,高度代表每个数出现的次数。从图像上理解,分割出的连续子序列,相当于
在直方图上某一高度截取的几个值的宽度大于等于3的一段,而且这几个值同高度的部分一定是连续的。
所以开辟数组,当高度上升时,存放某个高度的起点,高度下降时,比较相同高度的起点,若宽度<3则不可分割
*/
問題の公式ソリューションを参照し、ハッシュテーブルの機能を使用してキーを介して直接アクセスし、ハッシュテーブルを使用し
て各番号の出現回数を格納します。番号の前の番号で終わるサブシーケンスがある場合は、これ末尾に数字が追加されます。
存在しない場合は、この番号の最後の2つの番号を確認し、未使用の最後の2つの番号がある場合は、長さ3の新しいサブシーケンスを作成します。
ハッシュテーブルの特性上、境界条件を気にする必要はありません。
class Solution {
public:
bool isPossible(vector<int>& nums) {
int n = nums.size();
unordered_map<int,int> num;
unordered_map<int,int> end;
if(n <= 2){
return false;
}
for(auto i : nums){
num[i]++;
}
for(auto i : nums){
//i没被用完
if(num[i] > 0){
//存在以i-1为结尾的子序列
if(end[i-1] > 0){
end[i-1]--;
end[i]++;
num[i]--;
}else{
//不存在以i-1为结尾的子序列,只能新开辟一个子序列。查询i+1 i+2是否被用尽
if(num[i+1] > 0 && num[i+2] > 0){
num[i]--;
num[i+1]--;
num[i+2]--;
end[i+2]++;
}else{
return false;
}
}
}
}
return true;
}
};