leetcode 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
提示:
-
1 <= nums.length <= 104
-
-105 <= nums[i] <= 105
进阶:你可以设计一个时间复杂度为 O(n)
的解决方案吗?
Related Topics
栈
贪心
数组
双指针
排序
单调栈
思路1:排序
参考leetcode官方,对原有数组进行复制。
-
找到相同的前缀和后缀,那么中间的部分就是需要排序的子数组。
public int findUnsortedSubarray(int[] nums) { int[] copy = new int[nums.length]; int length = nums.length; for(int i = 0 ; i < length;i++){ copy[i] = nums[i]; } Arrays.sort(copy); int start = 0; while(start < length && nums[start] == copy[start]){ start++; } //判断nums是否本来就有序 如果有序 直接返回0 if(start == length){ return 0; } int end = length-1; while(end > start && nums[end] == copy[end]){ end--; } return end - start + 1; } 解答成功: 执行耗时:6 ms,击败了39.31% 的Java用户 内存消耗:42.3 MB,击败了5.01% 的Java用户
思路2:一次遍历
-
我们从左往右遍历,边遍历边确定遍历区间的最大值,如果当前值小于最大值,那么这个值肯定需要排序,这样就可以确定右边界。
-
我们从右往左遍历,边遍历边确定遍历区间的最小值,如果当前值大于最小值,那么这个值肯定需要排序,这样就可以确定左边界。
-
我们可以使用一次遍历直接进行从左往右和从右往左遍历。
public int findUnsortedSubarray(int[] nums) { int length = nums.length; int max = nums[0]; int min = nums[length-1]; int start = 0; int end = -1; for(int i = 0 ; i < length;i++){ //从左往右确定右边界 if(max > nums[i]){ // i坐标的值需要排序 end = i; }else{//不需要 直接更新max的值 max = nums[i]; } //从右往左确定左边界 if(min < nums[length - i - 1]){ // 需要排序 start = length - i - 1; }else{//不需要排序 更新最小值 min = nums[length - i - 1]; } } // 如果nums本来就有序 那么start和end不变化返回0 // 但是如果有无序的子数组,那么需要使用end - start + 1 // 所以直接将start = -1; // end = 0 return end - start + 1; } 解答成功: 执行耗时:1 ms,击败了99.18% 的Java用户 内存消耗:41.9 MB,击败了7.33% 的Java用户