持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第7天,点击查看活动详情
每日刷题 2022.10.04
- leetcode原题链接:leetcode.cn/problems/sh…
- 难度:中等
题目
- 给你一个整数数组 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
提示
1 <= nums.length <= 104
-105 <= nums[i] <= 105
进阶: 你可以设计一个时间复杂度为 O(n)
的解决方案吗?
解题思路
- 先说关键点:start是从后往前遍历数组,最后一个非降序的下标(比如[5,6,3,4],5,6就是非降序的,5是最后一个非降序的);end是从前往后遍历数组,最后一个非升序的下标
- 寻找start
- 因为nums[start]不是[start, end]范围内最小的,如果它是范围内最小,那nums[start]就是有序数组的一部分,而start之前的A是有序数组,从后往前是降序的,所以start是从后往前遍历数组,最后一个非降序的下标
- 下面就利用这个特点:从后往前遍历数组,如果在C范围遍历,数组降序(更新下标min,min是连续的),如果在B范围遍历,数组非降序(min不是连续的,将大于上一个min的用start'表示),如果在A范围内遍历,数组降序(min是连续的),因为start是从后往前遍历数组,最后一个非降序的下标,所以start'最终会更新为start
- 寻找end
- 因为nums[end]不是[start, end]范围内最大的,如果它是范围内最大,那nums[end]就是有序数组的一部分,而end之后的C是有序数组,从前往后是升序的,所以end是从前往后遍历数组,最后一个非升序的下标
- 下面就利用这个特点:从前往后遍历数组,如果在A范围遍历,数组升序(更新下标max,max是连续的),如果在B范围内遍历,数组非升序(max不是连续的,将小于上一个max的用end'表示),如果在C范围内遍历,数组升序(max是连续的),因为end是从前往后遍历数组,最后一个非升序的下标,所以end'最终会更新为end
AC
代码
/**
* @param {number[]} nums
* @return {number}
*/
var findUnsortedSubarray = function(nums) {
let n = nums.length, l = 0, r = n - 1;
while(l < r && nums[l] <= nums[l + 1]) {
l++;
}
while(r >= 0 && nums[r] >= nums[r - 1]) {
r--;
}
// find it
let minn = Infinity, maxx = -Infinity;
for(let i = l; i <= r; i++) {
minn = Math.min(minn, nums[i]);
maxx = Math.max(maxx, nums[i]);
}
while(nums[l] > minn) {
l--;
}
while(nums[r] < maxx) {
r++;
}
console.log(l, r, minn, maxx)
return r > l ? r - l - 1 : 0;
};