[LeetCode] 581. Shortest Unsorted Continuous Subarray

42 篇文章 0 订阅
37 篇文章 0 订阅

题目链接: https://leetcode.com/problems/shortest-unsorted-continuous-subarray/description/

Description

Given an integer array, you need to find one continuous subarray that if you only sort this subarray in ascending order, then the whole array will be sorted in ascending order, too.

You need to find the shortest such subarray and output its length.

Example 1:

Input: [2, 6, 4, 8, 10, 9, 15]
Output: 5
Explanation: You need to sort [6, 4, 8, 10, 9] in ascending order to make the whole array sorted in ascending order.

Note:

  1. Then length of the input array is in range [1, 10,000].
  2. The input array may contain duplicates, so ascending order here means <=.

解题思路

方法一:
先从数组两侧往中间分别找第一个无序的位置,即第一个下标 i 满足 nums[i] > nums[i + 1] 和第一个下标 j 满足 nums[j - 1] > nums[j]。可以确定区间 [i, j] 是目标区间的一个子集,因为在区间 [i, j] 中可能有比 [0, i - 1] 区间内某个数更小的数和比 [j + 1, n] 区间内某个数更大的数。所以,我们要遍历区间 [i, j],找到最小值 minNum 和最大值 maxNum,然后向两侧扩充,往左找到第一个小于等于 minNum 的元素值下标 i,往右找到第一个大于等于 maxNum 的元素值下标 j,此时区间 [i + 1, j - 1] 即为目标区间。

方法二:
使用栈 s 来维持一个递增或递减序列的下标,区间的上下界分别用 startend 记录。

先从左往右遍历一次数组 nums 以确定目标区间的下界,对每一个元素 nums[i],比较栈顶对应的数组元素 nums[s.top()] 是否大于 nums[i],若大于则更新 start = min(start, s.top()) 并出栈,重复直到栈为空或 nums[s.top()] <= nums[i],将当前下标 i 入栈。这样遍历完一次后,start 的值就变成目标区间的上界了。

在对数组从右往左遍历一次,用类似的方法可以确定目标区间的下界 end

举个例子,nums = [2, 6, 4, 8, 10, 9, 15] 后面为循环比较后的栈内元素,最左边为栈底,

  • 从左往右遍历
    • 2[0]
    • 6[0, 1]
    • 4[0, 2],更新 start = 1
    • 8[0, 2, 3]
    • 10[0, 2, 3, 4]
    • 9[0, 2, 3, 5],4 大于 1,start 值不变
    • 15[0, 2, 3, 5, 6]
  • 从右往左遍历
    • 15[6]
    • 9[6, 5]
    • 10[6, 4],更新 end = 5
    • 8[6, 4, 3]
    • 4[6, 4, 3, 2]
    • 6[6, 4, 3, 1],2 小于 5,end 值不变
    • 2[6, 4, 3, 1, 0]

目标区间为 [1, 5]

Code

方法一:

class Solution {
public:
    int findUnsortedSubarray(vector<int>& nums) {
        // 从两端向内找到第一个无序的位置
        int i = 0, j = nums.size() - 1;
        while (i < nums.size() - 1 && nums[i] <= nums[i + 1])
            i++;
        while (j > 0 && nums[j - 1] <= nums[j])
            j--;
        if (i >= j) return 0;

        // 在 nums[i..j] 中找最小值 minNum 和最大值 maxNum
        int minNum = INT_MAX, maxNum = INT_MIN;
        for (int k = i; k <= j; k++) {
            minNum = min(minNum, nums[k]);
            maxNum = max(maxNum, nums[k]);
        }

        // 为确保 nums[0...i - 1] <= minNum 和 nums[j + 1...n] >= maxNum 向外扩展
        while (i >= 1 && nums[i - 1] > minNum)
            i--;
        while (j < nums.size() - 1 && nums[j + 1] < maxNum)
            j++;

        return j - i + 1;
    }
};

方法二:

class Solution {
public:
    int findUnsortedSubarray(vector<int> &nums) {
        int start = nums.size(), end = 0;
        stack<int> s;
        for (int i = 0; i < nums.size(); ++i) {
            while (!s.empty() && nums[i] < nums[s.top()]) {
                start = min(start, s.top());
                s.pop();
            }
            s.push(i);
        }

        while (!s.empty()) s.pop();

        for (int i = nums.size() - 1; i >= 0; --i) {
            while (!s.empty() && nums[i] > nums[s.top()]) {
                end = max(end, s.top());
                s.pop();
            }
            s.push(i);
        }

        return start < end ? end - start + 1 : 0;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值