[M双指针] lc581. 最短无序连续子数组(线性扫描+细节处理+算法优化)

Posted Ypuyu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[M双指针] lc581. 最短无序连续子数组(线性扫描+细节处理+算法优化)相关的知识,希望对你有一定的参考价值。

1. 题目来源

链接:581. 最短无序连续子数组

2. 题目解析

不错的题目,两种做法。

方法一:暴力排序+找两侧端点不同点

  • 直接排序,找到排序后与排序前左右两端第一个出现不同的地方,返回区间长度即可。

  • 时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)
  • 空间复杂度 O ( n ) O(n) O(n)

方法二:线性扫描

  • 假设我们找到了答案区间,记区间端点为 [l, r],那么 [0, l) 区间中一定是升序的,且 nums[l-1] 一定小于 [l, n) 区间的所有数。因为后面重排序后是要单调递增的。
  • 同理,针对右区间端点也是同理。 nums[r+1] 是要大于 [0, r] 之间的所有数的。
  • 先将初始数组的升序部分先跳过,先得到一个 l, r 然后再分别找到 [l+1, n) 的最小值 mi[0, r-1] 的最大值 mx
  • l 所处位置要比后半段最小值还要小,r 所处位置要不前半段最大值还要大。由于预先处理的 l,r 已经单调递增,故直接找即可。
  • 最终,l, r 将停在非法位置,答案区间长度即为 r-l-1

  • 时间复杂度 O ( n ) O(n) O(n)
  • 空间复杂度 O ( 1 ) O(1) O(1)

代码:

方法一:直接排序+找不同点

class Solution {
public:
    int findUnsortedSubarray(vector<int>& nums) {
        int n = nums.size();
        vector<int> q = nums;
        sort(q.begin(), q.end());
        int l = 0, r = n - 1;
        while (l < n && nums[l] == q[l]) l ++ ;
        while (r >= 0 && nums[r] == q[r]) r -- ;
        if (l >= r) return 0;

        return r - l + 1;
    }
};

方法二:双指针+线性扫描

class Solution {
public:
    int findUnsortedSubarray(vector<int>& nums) {
        int n = nums.size();
        int l = 0, r = n - 1;
        while (l + 1 < n && nums[l + 1] >= nums[l]) l ++ ;
        if (l == r) return 0;
        while (r - 1 >= 0 && nums[r - 1] <= nums[r]) r -- ;
        int mi = 1e9, mx = -1e9;
        for (int i = l + 1; i < n; i ++ ) mi = min(mi, nums[i]);
        for (int i = r - 1; i >= 0; i -- ) mx = max(mx, nums[i]);
        while (l >= 0 && nums[l] > mi) l -- ;       // 在此不应该用 >=
        while (r < n && nums[r] < mx) r ++ ;        // 在此不应该用 <=,不存在相邻情况

        return r - l - 1;
    }
};

以上是关于[M双指针] lc581. 最短无序连续子数组(线性扫描+细节处理+算法优化)的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode 581 最短无序连续子数组[排序] HERODING的LeetCode之路

581-最短无序连续子数组

LeetCode 581. 最短无序连续子数组(Shortest Unsorted Continuous Subarray)

Leetcode 581.最短无序连续子数组

leetcode581 最短无序连续子数组(Easy不简单)

数组581. 最短无序连续子数组