581. 最短无序连续子数组

给你一个整数数组 nums ,你需要找出一个 连续子数组 ,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。

请你找出符合题意的 最短 子数组,并输出它的长度。

前言---::这题我并没有想到思路,在最后看了题解后将自己的理解记录在这

简单理解的思路是:先找到第一个前面和后面不满足条件的的位置,然后记录中间这段(这段必须算上left位置和right位置,因为这两个位置分别是前后两段的最大最小值)的最大最小值,然后看是否临近的数在中间乱序数组的范围内,则加入到乱序数组中。如图:

问题描述

给定一个整数数组 nums,我们需要找出一个 连续子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。我们的目标是找出符合要求的 最短子数组 并输出它的长度。

思路分析

这个问题可以通过寻找“局部无序区间”来解决。整个数组从左到右遍历,找到第一个不满足升序的子数组的左边界和右边界,并计算出该区间的最小值和最大值,借助这些信息确定需要排序的子数组范围。

我们将分为以下几个步骤:

  1. 找到左边界:从数组的左侧开始,直到遇到一个不满足升序的点。即,找出第一个出现逆序的位置。
  2. 找到右边界:从数组的右侧开始,直到遇到一个不满足升序的点。即,找出第一个出现逆序的位置。
  3. 找到最小值和最大值:在步骤 1 和步骤 2 找到的范围内,找出最小值和最大值。
  4. 重新确定边界:遍历数组的左边部分和右边部分,确定真正的左边界和右边界,直到子数组中的最小值大于左边界,最大值小于右边界。

通过这种方式,我们能够找到最小的无序子数组,并返回其长度。

class Solution {
public:
    int findUnsortedSubarray(vector<int>& nums) {
        int left = 0, right = nums.size() - 1;
        
        // 找到从左边第一个不满足升序的点
        while (left < right && nums[left + 1] >= nums[left]) {
            left++;
        }
        
        // 如果整个数组已经有序
        if (left == right) return 0;
        
        // 找到从右边第一个不满足升序的点
        while (right > 0 && nums[right - 1] <= nums[right]) {
            right--;
        }
        
        int minnum = INT_MAX, maxnum = INT_MIN;
        
        // 在[left, right]区间内,找到最小值和最大值
        for (int i = left; i <= right; i++) {
            minnum = min(minnum, nums[i]);
            maxnum = max(maxnum, nums[i]);
        }
        
        // 扩展左边界,直到找到小于等于最小值的位置
        while (left >= 0 && nums[left] > minnum) {
            left--;
        }
        
        // 扩展右边界,直到找到大于等于最大值的位置
        while (right < nums.size() && nums[right] < maxnum) {
            right++;
        }
        
        // 返回最短无序子数组的长度
        return right - left - 1;
    }
};

代码解析

  1. 初始化左右指针
    • left 指向数组的第一个元素,right 指向数组的最后一个元素。
  2. 确定左边界
    • 使用 while 循环找到左边第一个不满足升序的元素,即 nums[left + 1] >= nums[left] 的条件不再成立。
  3. 确定右边界
    • 同样的方式,使用 while 循环从右边找到第一个不满足升序的元素。
  4. 计算最小值和最大值
    • 在从 leftright 的区间内,找到最小值 minnum 和最大值 maxnum
  5. 扩展左右边界
    • 向左扩展边界,直到找到比最小值大的元素。
    • 向右扩展边界,直到找到比最大值小的元素。
  6. 返回结果
    • 最后返回 right - left - 1,即为最短无序子数组的长度。

时间复杂度

  • 时间复杂度:O(n),其中 n 是数组的长度。我们只遍历了数组几次,时间复杂度是线性的。
  • 空间复杂度:O(1),我们只使用了常数级别的额外空间。

关键点总结

  1. 找到无序区间的边界:通过不断寻找满足升序的条件,快速确定左边界和右边界。
  2. 通过最小值和最大值扩展边界:通过查找 leftright 范围内的最小值和最大值,确保子数组被正确扩展。
  3. 无需排序:本题巧妙地通过比较而非排序来定位无序子数组。

总结

这个问题的核心在于找出最小的不符合升序的区间,然后扩展这个区间直到整个数组有序。该方法避免了直接排序数组,从而实现了高效的 O(n) 时间复杂度解决方案。希望通过这篇博客的分享,大家对如何优化寻找最短无序子数组的算法有了更深的理解。如果你有任何问题,欢迎在评论区留言讨论!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值