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

题目链接:1574. 删除最短的子数组使剩余数组有序

方法:双指针 + 找规律

解题思路

去除子数组的可能情况:

  1. 将第一个递减序列的左端点到末尾的子数组去掉;

  2. 将最后一个递减序列的右端点到起点的子数组去掉;

  3. 左端点:起点 和 第一个递减序列的左端点之间取,
    右端点:最后一个递减序列的右端点和末尾之间取,
    使得\([l, r]\)最小,且去除后符合条件。

代码

static const auto io_sync_off = []() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    return nullptr;
}();

class Solution {
public:
    int findLengthOfShortestSubarray(vector<int>& arr) {
        int n = arr.size();
        int startLeft = 0, endRight = n - 1; // 分别表示第一个递减序列的左端点 和 最后一个递减序列的右端点
        while (startLeft < n - 1 && arr[startLeft] <= arr[startLeft + 1]) startLeft ++ ;
        if (startLeft == n - 1) return 0; // 此时数组自身非递减
        while (endRight && arr[endRight - 1] <= arr[endRight]) endRight -- ;
        if (arr[endRight] >= arr[startLeft]) return endRight - startLeft - 1; // 判断最短情况是否成立
        int ans = min(n - startLeft - 1, endRight); // 取1和2中的最小值
        for (int l = 0, r = endRight; r < n && l <= startLeft; ) { // 取ans和3中的最小值
            // 找第一个大于等于arr[l]的下标,保证r距离l最近
            r = lower_bound(arr.begin() + r, arr.end(), arr[l]) - arr.begin(); 
            if (r < n) {
                // 找第一个大于arr[r]的下标,保证l距离r最近
                l = upper_bound(arr.begin() + l, arr.begin() + startLeft + 1, arr[r]) - arr.begin(); 
                ans = min(ans, r - l); 
            }
        }
        return ans == n ? ans - 1 : ans;
    }
};

复杂度分析

时间复杂度:\(O(n)\)
空间复杂度:\(O(1)\)

posted @ 2023-04-09 00:03  lixycc  阅读(34)  评论(0)    收藏  举报