leetcode hot100之最短无序连续子数组(581)解析

104 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第17天,点击查看活动详情


前言

  • leetcode hot100,是大厂面试高频题,也是必刷算法题。精选了100道LeetCode上最热门的题目,适合初识算法与数据结构的新手和想要在短时间内高效提升的人,按照官方说的,熟练掌握这 100 道题,就具备了代码世界通行的基本能力。

leetcode581题(最短无序连续子数组

本文来讲hot100第581题,最短无序连续子数组,本题题目比较容易理解,建议画张图,方便我们找到边界值。

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

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

示例:

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

进阶: 你可以设计一个时间复杂度为 O(n) 的解决方案吗?

分析

  1. 找到连续子数组,是一个区间,中间不能断,数组的长度最少为2
  2. 这段整数组进行升序排序,则整个数组都升序排序,所以我们可以知道除了子数组以外的数字,也是升序排列。

思路

由分析可知,我们需要找到边界,所以我们使用双指针法

  1. 我们先从左右两边分别遍历,知道不满足升序数组的边界
  2. 在两个边界内找到其中的最大值 max,以及最小值 min,
  3. 需要把左指针往左找到比 min 小的第一个数
  4. 需要把右指针往右找到比 max 大的第一个数
  5. 此时左指针和右指针中间的数,就是我们要找的排序的数

代码

var findUnsortedSubarray = function(nums) {
  // 1. 双指针找边界
  // 2. 找边界内的最大最小数
  // 3. index相减
  let len = nums.length, start = 0, end = len - 1
  while (start < len - 1 && nums[start] <= nums[start + 1]) {
    start ++
  }

  while (end > 0 && nums[end - 1] <= nums[end]) {
    end --
  }
  // 设置最小值与最大值
  let min = Infinity, max = -Infinity
  // 注意这里是左闭右闭
  for (let i = start; i <= end; i ++) {
    min = Math.min(nums[i], min)
    max = Math.max(nums[i], max)
  }
  // 因为我们第一次双指针找到不满足条件就不找了,所以边界是有可能不对的
  // 如果与min小于最左边的值或者max大于最右边的值,说明我们找到边界不对,需要更新边界
  while (nums[start] > min) {
    start --
  }

  while (nums[end] < max) {
    end ++
  }

  return end > start ? end - start - 1: 0

};

结语

  1. 此题也可以使用暴力法,既然题目是种类类型难度,那么我们肯定要用进阶的时间复杂度解决问题,此题的时间复杂度为O(n)