前后扫描法(时间复杂度 O(n)
)
【找到从前往后
最后一个比前半部分当前最大值
小的】
【找到从后往前
最后一个比后半部分当前最小值
大的】
- 寻找左右边界的核心关键:
逆序对!
- 对于完全符合条件的序列(即完全有序),应该是没有逆序对存在的!
- 所以本题的无序序列的左右边界
- 其实就是**左边界的前面的元素与其后所有元素严格顺序; 右边界后面的元素,与前面所有元素严格顺序**
- 比如:
2| 6, 4, 8, 10, 9| 15
- 其中
2
和后面的所有元素严格顺序! - 而
15
和前面的所有元素严格顺序! - 所以寻找左右边界的流程就是:
2| 6, 4, 8, 10, 9| 15
从左往右
(------->)- 先将第一个值设为当前
max
- nums[i]
>=
max,构成顺序对
,更新 max = nums[i]- 比如:
2
,6
此时max ==2 , nums[i] == 6 , 由于6 > 2
, 所以更新max =6
;
- 比如:
- nums[i]
<
max,构成了逆序对
,更新无序右边界 right = i- 比如 :
6
,4
此时max ==6 , nums[i] == 4 , 由于4 < 6
, 所以更新右边界 right = 2
;
- 比如 :
- nums[i]
- 先将第一个值设为当前
从右往左
: (<-------)- 先将最后一个值设为
min
- nums[i]
<=
min ,更新 min ; - nums[i]
>
min ,构成逆序对,更新无序左边界 left = i
- nums[i]
- 先将最后一个值设为
- 比如:
// 代码中,将上述两个遍历过程合成了一个遍历过程
public int findUnsortedSubarray(int[] nums) {
int len = nums.length;
// max :表示当前遍历的元素的最大值 从前往后
// min :表示当前遍历元素的最小值 从后往前
int max = nums[0];
int min = nums[len - 1];
int left = 0, right = -1;
for (int i = 0; i < len; i++) {
// 右边界
if (max <= nums[i]) {
max = nums[i];
} else {
right = i;
}
// 左边界
if (min >= nums[len - i - 1]) {
min = nums[len - i - 1];
} else {
left = len - i - 1;
}
}
return right - left + 1;
}
}