Given an integer array nums, you need to find one continuous subarray that if you only sort this subarray in ascending order, then the whole array will be sorted in ascending order.
Return the shortest such subarray and output its length.
Example 1:
Input: nums = [2,6,4,8,10,9,15]
Output: 5
Explanation: You need to sort [6, 4, 8, 10, 9] in ascending order to make the whole array sorted in ascending order.
简言之就是找出大的排序数组中未排序的部分的长度
思路:
(1) 可以另外建一个数组,保存与nums一样的元素,但是排序。
然后一一对比,从左边遍历,发现顺序不对的index保存到start,再从右边遍历,遇到顺序不一致的index保存为end,最后未排序部分的长度为end-start+1
public int findUnsortedSubarray(int[] nums) {
if(nums == null || nums.length == 0) {
return 0;
}
int n = nums.length;
int[] tmp = nums.clone();
Arrays.sort(tmp);
int start = -1;
int end = -2;
for(int i = 0; i < n; i++) {
if(tmp[i] != nums[i]) {
start = i;
break;
}
}
for(int i = n -1; i >= 0; i--) {
if(tmp[i] != nums[i]) {
end = i;
break;
}
}
return end-start+1;
}
(2) 简化上面的方法,从左到右应是升序的,从右到左应是降序的。
比如数组 1,2,3,XXX,9,10,11
我们知道中间这XXX的部分是需要重新排序的,才能整体升序,
所以这XXX部分的最小值unsortedMin也要比左边最右边的3大,
XXX部分的最大值unsortedMax也会比最右边的最小值9小。
然而也可以知道这个unsortedMin肯定不在最左边,不然就是正常的升序了,XXX就不从它开始了,
同理unsortedMax也不在最右边,不然XXX就不包含它了是吧。
所以,XXX部分的左边界数字应该是从右到左最后一个比unsortedMin大的数字(再往左所有数字都会比它小),
而XXX部分的右边界一定是从左到右最后一个比unsotedMax小的数字(再往右所有数字都比它大了)。
所以,从左到右,同时从右到左同时遍历数组,找出上面条件的边界即可。
注意start和end的初始化,在数组一直是正确顺序时,未排序部分的长度应该为0,即初始的end - start + 1应等于0.
public int findUnsortedSubarray(int[] nums) {
int n = nums.length;
int unsortedMax = nums[0];
int unsortedMin = nums[n-1];
int start = -1;
int end = -2;
for(int i = 0; i < n; i++) {
//从前往后找不排序部分的最大值
unsortedMax = Math.max(unsortedMax, nums[i]);
//从后往前找不排序部分的最小值
unsortedMin = Math.min(unsortedMin, nums[n - 1 - i]);
//更新最后一个比 不排序部分最大值 小的index
//因为后面的排序部分都要比这部分的所有值大
if(nums[i] < unsortedMax) {
end = i;
}
//更新最前面一个比 不排序部分最小值 大的index
//因为前面排序的部分必是比这部分的所有值都小的
if(nums[n - 1 - i] > unsortedMin) {
start = n - 1 - i;
}
}
return (end - start + 1);
}