题目描述:
给你一个整数数组 arr
,请你删除一个子数组(可以为空),使得 arr
中剩下的元素是 非递减 的。
一个子数组指的是原数组中连续的一个子序列。
请你返回满足题目要求的最短子数组的长度。
示例 1:
输入:arr = [1,2,3,10,4,2,3,5]
输出:3
解释:我们需要删除的最短子数组是 [10,4,2] ,长度为 3 。剩余元素形成非递减数组 [1,2,3,3,5] 。
另一个正确的解为删除子数组 [3,10,4] 。
示例 2:
输入:arr = [5,4,3,2,1]
输出:4
解释:由于数组是严格递减的,我们只能保留一个元素。所以我们需要删除长度为 4 的子数组,要么删除 [5,4,3,2],要么删除 [4,3,2,1]。
示例 3:
输入:arr = [1,2,3]
输出:0
解释:数组已经是非递减的了,我们不需要删除任何元素。
示例 4:
输入:arr = [1]
输出:0
提示:
1 <= arr.length <= 10^5
0 <= arr[i] <= 10^9
解题思路:
1)、首先寻找递减(arr[i] > arr[i + 1]
) 趋势的位置信息记录在vector<int> loc
;
2)、如果整个序列呈现非递减趋势,即loc.size() == 0
;不需要删除;
3)、按照loc的首位,末尾(留首去尾)pre = loc[0] (第一段) , aft = loc.back() + 1;(第二一段)
,在pre-->aft
是一定要删除的部分;
maxNum = max(ret , pre + 1);
//记录被保留的长度;
按照拼接两个序列的思路,假设第二个序列全被保留ret = arr.size() - loc.back() - 1;
按照 第一个序列前进 +1 ,第二序列前进-1 ;
比较 maxNum = max(maxNum , ret) ;
被保留的序列的长度;
最后使用 arr.size() - maxNum ;
即为要删除的子串的长度;
代码实现:
class Solution {
public:
int findLengthOfShortestSubarray(vector<int>& arr) {
int i = 0 ;
vector<int> loc ;
//找到出现下降趋势的起始点;
for (i = 0 ; i < arr.size() - 1 ; i ++)
if (arr[i] > arr[i + 1]) loc.push_back(i) ;
if (loc.size() == 0) return 0 ;
int pre = loc[0] + 1 , aft = loc.back() + 1;
int ret = arr.size() - loc.back() - 1;
int maxNum = max(ret , pre);//记录有效的子串的长度;
i = 0;
//将分割好的两个子串,按照从小到大的顺序遍历,右边进一步-1,左边的进一步+1 ;
while(i < pre && aft < arr.size())
{
if (arr[i] <= arr[aft])
{
i ++ ;
ret ++ ;
maxNum = max(maxNum , ret) ;
}
else{
aft ++ ;
ret -- ;
}
}
//返回删除的子串的长度 = arr.size() - 有效的序列长度;
return arr.size() - maxNum ;
}
};
复杂度计算:
时间复杂度:O(n)
;
空间复杂度:最大O(n - 1)
;全序列呈现递减趋势,即为:arr[i] > arr[i + 1]
;