【贪心-4】581.最短无序连续子数组

题目描述:

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

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

示例 1:

复制代码
输入:nums = [2,6,4,8,10,9,15]
输出:5
解释:你只需要对 [6, 4, 8, 10, 9] 进行升序排序,那么整个表都会变为升序排序。

示例 2:

复制代码
输入:nums = [1,2,3,4]
输出:0

示例 3:

复制代码
输入:nums = [1]
输出:0

解题思路:

方法一:双指针(贪心思想,最优)

思路:

数组可以分成三段:有序前缀 + 无序中段 + 有序后缀。

  • 左边界 :从左往右扫描,维护左边最大值 maxNum。如果 nums[i] < maxNum,说明 i 在无序区域内,更新 low = i。

  • 右边界 :从右往左扫描,维护右边最小值 minNum。如果 nums[i] > minNum,说明 i 在无序区域内,更新 high = i。

  • 结果 :low - high + 1 就是最短无序子数组的长度。

代码实现:

cpp 复制代码
class Solution {
public:
    int findUnsortedSubarray(vector<int>& nums) {
        int n = nums.size();
        if (n <= 1) return 0;
        
        int low = 0, high = n - 1;
        int maxNum = nums[0], minNum = nums[n - 1];
        
        for (int i = 1; i < n; i++) {
            // 从左往右:维护最大值,找最右边的乱序位置
            maxNum = max(maxNum, nums[i]);
            if (nums[i] < maxNum) low = i;
            
            // 从右往左:维护最小值,找最左边的乱序位置
            minNum = min(minNum, nums[n - 1 - i]);
            if (nums[n - 1 - i] > minNum) high = n - 1 - i;
        }
        
        return low > high ? low - high + 1 : 0;
    }
};

复杂度分析:

维度 复杂度 说明
时间复杂度 O(n) 一次遍历
空间复杂度 O(1) 只用常数个变量

优缺点:

优点 缺点
✅ 时间复杂度 O(n),最优 ❌ 思路不直观,需要理解"乱序"的判断
✅ 空间复杂度 O(1) ❌ 边界条件容易写错(如 low > high 的判断)
✅ 一次遍历同时找左右边界
✅ 面试首选

方法二:排序 + 双指针

思路:

  1. 把原数组复制一份并排序。

  2. 对比排序后的数组和原数组:

    • 从左往右找到第一个不同的位置 l

    • 从右往左找到最后一个不同的位置 r

  3. r - l + 1 就是最短无序子数组的长度。

代码实现:

cpp 复制代码
class Solution {
public:
    int findUnsortedSubarray(vector<int>& nums) {
        vector<int> sorted = nums;
        sort(sorted.begin(), sorted.end());
        
        int l = 0, r = nums.size() - 1;
        while (l <= r && nums[l] == sorted[l]) l++;
        while (l <= r && nums[r] == sorted[r]) r--;
        
        return r - l + 1;
    }
};

复杂度分析:

维度 复杂度 说明
时间复杂度 O(n log n) 排序
空间复杂度 O(n) 复制一份数组

优缺点:

优点 缺点
✅ 思路直观,容易理解 ❌ 时间复杂度 O(n log n),不是最优
✅ 代码简洁,不易出错 ❌ 需要额外 O(n) 空间
✅ 适合快速写出答案 ❌ 面试官可能追问"能否 O(n)"

两种方法对比:

对比维度 双指针 + 线性扫描 排序 + 双指针
时间复杂度 O(n) O(n log n)
空间复杂度 O(1) O(n)
代码复杂度 中等 简单
是否修改原数组 ❌ 不修改 ❌ 不修改
相关推荐
careathers5 分钟前
【数据结构】从堆到 PriorityQueue:手写一个优先级队列
数据结构
y1su1 小时前
Leetcode 字符串模板
java·数据结构·算法·leetcode·职场和发展·动态规划
residual_fan2 小时前
船用柴油机动态机动工况故障诊断:控制感知仿射网络(CAAN)的技术实现
人工智能·算法·数据挖掘·数据分析
syagain_zsx2 小时前
BRpc 二次封装:Channel 管理、服务管理与回调工厂
c++·学习·程序人生·rpc·谷歌
其实防守也摸鱼2 小时前
Cylab在线靶场——CTF中的通用技能
linux·数据库·学习·算法·靶场·ctf·学习网络安全
蓝悦无人机3 小时前
《Planning algorithms》读书笔记——第8章 反馈运动规划
算法·读书笔记·反馈运动规划
RaaS1003 小时前
Agent Skills 进了 Linux Foundation:2.8 亿次安装,但装 skill 还没有安全规范
人工智能·算法·架构
CV爱数码3 小时前
CT 重建从零开始(五):ASTRA Toolbox 上手——几何、投影器与算法
图像处理·算法·计算机视觉·ct
TunerT_TQ3 小时前
超立方体Ramsey(openai/math 家族171)H11攻坚日志|D60–D69:Star分组重数、二幂坐标群、奇偶入射语义与Site‑Level候选计数形式化闭环
算法
fpcc3 小时前
计算机原理—如何高效的操作文件
c++·计算机原理