leetcode:1574. 删除最短的子数组使剩余数组有序

题目

给你一个整数数组 arr ,请你删除一个子数组(可以为空),使得 arr 中剩下的元素是 非递减 的。
一个子数组指的是原数组中连续的一个子序列。
请你返回满足题目要求的最短子数组的长度。

示例:

  1. 输入:arr = [1,2,3,10,4,2,3,5]
  2. 输出:3
  3. 解释:我们需要删除的最短子数组是 [10,4,2] ,长度为 3 。剩余元素形成非递减数组 [1,2,3,3,5]
  4. 另一个正确的解为删除子数组 [3,10,4]
输入:arr = [5,4,3,2,1]
输出:4
解释:由于数组是严格递减的,我们只能保留一个元素。所以我们需要删除长度为 4 的子数组,要么删除 [5,4,3,2],要么删除 [4,3,2,1]。
输入:arr = [1,2,3]
输出:0
解释:数组已经是非递减的了,我们不需要删除任何元素。
输入:arr = [1]
输出:0

解答 & 代码

同向双指针(滑动窗口)
image.png

class Solution {
public:
    int findLengthOfShortestSubarray(vector<int>& arr) {
        int len = arr.size();
        // 定位到左边非递减序列的终点,使得 [0, leftEnd] 为非递减序列
        int leftEnd = 1;
        while(leftEnd < len && arr[leftEnd] >= arr[leftEnd - 1])
            ++leftEnd;
        if(leftEnd == len)    // 如果 arr 数组本身有序,则无需删除,因此直接返回 0
            return 0;
        --leftEnd;
        // 定位到右边非递减序列的起点,使得 [rightStart, len) 为非递减序列
        int rightStart = len - 2;
        while(rightStart >= 0 && arr[rightStart] <= arr[rightStart + 1])
            --rightStart;
        ++rightStart;

        // case 1:只保留左边非递减序列,则需要删除其右边剩余的长为 len - leftEnd - 1 的子数组
        // case 2:只保留右边非递减序列,则需要删除其左边剩余的长为 rightStart 的子数组
        // result 初始取两者最小值
        int result = min(len - leftEnd - 1, rightStart);
        // case 3:删除中间的某段连续子数组(窗口)。要获取最短的窗口长度
        // 同向双指针(滑动窗口),分别在左边非递减序列、右边非递减序列滑动
        int left = 0;                
        int right = rightStart;
        while(left <= leftEnd && right < len)
        {
            // [0, left] 和 [right, len-1] 可以连起来形成非递减序列,
            // 说明删掉窗口 [left + 1, right - 1] 即可得到非递减序列(窗口合法)
            if(arr[left] <= arr[right])    
            {
                result = min(result, right - left - 1);    // 取窗口长度更新 reuslt
                ++left;                                    // 滑动 left 指针
            }
            // arr[left] > arr[right],而 left 右边的数只会更大,
            // 因此需要右移 right 找到比 arr[left] 大的位置(窗口不合法)
            else                        
                ++right;                                // 滑动 right 指针,使得 arr[right] 增大
        }
        return result;
    }
};

复杂度分析:设数组 arr 长为 N

  • 时间复杂度 O(N):
  • 空间复杂度 O(1):

执行结果:

执行结果:通过

执行用时:104 ms, 在所有 C++ 提交中击败了 44.37% 的用户
内存消耗:65.2 MB, 在所有 C++ 提交中击败了 69.37% 的用户