5493. 删除最短的子数组使剩余数组有序

题目描述:

给你一个整数数组 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];

猜你喜欢

转载自blog.csdn.net/u010155337/article/details/108428457