题目描述

image.png

解题思路

排序做法

可以将数组排序之后,其中的区间不一样的地方就是最短无序的数组。
image.png
此时我们要找到该区间的左右边界,因为在这个区间中间可能还有顺序未改变的情况,所以要从左向右昭最小边界,从右向左找最大边界。

  1. class Solution {
  2. public int findUnsortedSubarray(int[] nums) {
  3. // 如果本来就是升序
  4. if (isSort(nums)) return 0;
  5. // 拷贝数组
  6. int[] temp = new int[nums.length];
  7. for (int i = 0; i < nums.length; i++) {
  8. temp[i] = nums[i];
  9. }
  10. // 可以使用
  11. // System.arraycopy(nums, 0, temp, 0, nums.length);
  12. // 找到排序后的左右不相等的边界
  13. int left = 0, right = nums.length - 1;
  14. Arrays.sort(temp);
  15. while (temp[left] == nums[left]) {
  16. left++;
  17. }
  18. while (temp[right] == nums[right]) {
  19. right--;
  20. }
  21. return right - left + 1;
  22. }
  23. public boolean isSort(int[] nums) {
  24. for (int i = 1; i < nums.length; i++) {
  25. if (nums[i - 1] > nums[i]) return false;
  26. }
  27. return true;
  28. }
  29. }

image.png

一次遍历

我们可以假设把这个数组分成三段,左段和右段是标准的升序数组,中段数组虽是无序的,但满足最小值大于左段的最大值,最大值小于右段的最小值。
image.png
那么我们目标就很明确了,找中段的左右边界,我们分别定义为begin 和 end;
分两头开始遍历:
从左到右维护一个最大值max,在进入右段之前,那么遍历到的nums[i]都是小于max的,我们要求的end就是遍历中最后一个小于max元素的位置;
同理,从右到左维护一个最小值min,在进入左段之前,那么遍历到的nums[i]也都是大于min的,要求的begin也就是最后一个大于min元素的位置。

注意找最左边界和最右边界的方法,右端所有数都大于中间区间最大值,左端所有值都小于中间区间最小值。所以小于max就更新索引,大于min就更新索引。

  1. // 一次遍历
  2. public int findUnsortedSubarray(int[] nums) {
  3. int len = nums.length;
  4. int max = nums[0];
  5. int min = nums[len - 1];
  6. // right初始化为-1,本来就是升序的情况,返回0
  7. int left = 0, right = len - 1;
  8. for (int i = 0; i < len; i++) {
  9. if (nums[i] < max) right = i;
  10. else max = nums[i];
  11. if (nums[len - i - 1] > min) left = len - i - 1;
  12. else min = nums[len - i - 1];
  13. }
  14. return right - left + 1;
  15. }