LeetCode581-最短无序连续子数组

题目链接

英文链接:https://leetcode.com/problems/shortest-unsorted-continuous-subarray/

中文链接:https://leetcode-cn.com/problems/shortest-unsorted-continuous-subarray/

题目详述

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

你找到的子数组应是最短的,请输出它的长度。

示例 1:

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

说明 :

  1. 输入的数组长度范围在 [1, 10,000]。
  2. 输入的数组可能包含重复元素 ,所以升序的意思是<=。

题目详解

方法一:

  • 将原数组拷贝一份,然后对拷贝后的数组进行排序。
  • 对比原数组和排序后的数组,除去前面一部分和后面一部分相同的元素,剩余区间的长度就是结果。
  • 时间复杂度为 O(nlogn)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class LeetCode_00581 {

public int findUnsortedSubarray(int[] nums) {
int[] sortedNums = Arrays.copyOf(nums, nums.length);
Arrays.sort(sortedNums);
int i = 0;
int j = nums.length - 1;
while (i <= j && nums[i] == sortedNums[i]) {
++i;
}
while (i <= j && nums[j] == sortedNums[j]) {
--j;
}
return j - i + 1;
}
}

方法二:

  • 分为两部分进行考虑。
  • 单独调整区间 [0 , r] 可使整个数组有序。
  • 单独调整区间 [l, n - 1] 可使整个数组有序。
  • 求出 l 和 r 后,调整区间 [l, r] 可使整个数组有序。
  • 所以问题转化为求 l 和 r,而 l 和 r 比较容易求出。
  • 时间复杂度为 O(n)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class LeetCode_00581 {

public int findUnsortedSubarray(int[] nums) {
int n = nums.length;
int max = nums[0]; // 从左往右的最大值
int min = nums[n - 1]; // 从右往左的最小值
int l = -1; // 需要调整的左边界
int r = -2; // 需要调整的右边界
for (int i = 1; i < n; ++i) {
max = Math.max(max, nums[i]);
if (nums[i] != max) {
r = i; // 从 r 向左单独调整,数组可以变为有序
}
min = Math.min(min, nums[n - 1 - i]);
if (nums[n - 1 - i] != min) {
l = n - 1 - i; // 从 l 向右单独调整,数组可以变为有序
}
}
// 数组已经有序时,l、r 不会变化(初始化为 -1、-2 避免单独判断)
return r - l + 1; // 调整 [l, r],数组可以变为有序
}
}