「这是我参与2022首次更文挑战的第16天,活动详情查看:2022首次更文挑战」
面试题 16.16. 部分排序
给定一个整数数组,编写一个函数,找出索引m和n,只要将索引区间[m,n]的元素排好序,整个数组就是有序的。注意:n-m尽量最小,也就是说,找出符合条件的最短序列。函数返回值为[m,n],若不存在这样的m和n(例如整个数组是有序的),请返回[-1,-1]。
示例:
输入: [1,2,4,7,10,11,7,12,6,7,16,18,19]
输出: [3,9]
提示:
0 <= len(array) <= 1000000
遍历找到最左和最右的位置
思路
由题意可知我们需要通过求解题目中乱序的一部分,将这部分排序后,整个数组将是一个有序的升序数组(题目中默认是升序排列,我也是控制台试出来的),并且这部分乱序的应该尽可能的短
如果数组长度为0或者是有序数组都返回[-1,-1]
这里我们先观察这个实例,我们可以发现中间乱序的部分满足的条件
- 如果一个值的右侧有一个比他小的值,那么比他小的值一定的乱序中的一部分,用来寻找r
- 同理如果一个值的左侧有一个比他大的值,那么比他大的值也是乱序中的,用来寻找l
具体实现:
- 正向遍历,寻找最右侧下标r,从左到右是升序排列,我们记录最大值,如果出现比当前最大值小的元素,那么符合刚才寻找r的条件,我们要寻找最右侧的r,那么就要找到比左侧最大值小的那个值
- 反向遍历,寻找最左的下标l,从右到左是降序排列,我们记录最小值,如果出现比当前最小值大的元素,那么复合刚才寻找l的条件,我们要寻找最左侧的l,那么就要找到比右侧最小值大的那个值
最后返回符合题意的lr即可,否则[-1,-1]
var subSort = function (array) {
// 从左往右找最大位置
// 该位置的值一定小于左侧的最大值、一定小于右侧的最小值
var l = -1, r = -1, len = array.length
if (len === 0) return [l, r]
var max = array[0]
for (var i = 1; i < len; i++) {
var item = array[i]
if (item >= max) {
max = item
} else {
r = i
}
}
// 从右往左找最小位置
// 该位置的值一定大于左侧的最大值、一定大于右侧的最小值
var min = array[len - 1]
for (var i = len - 2; i >= 0; i--) {
var item = array[i]
if (item <= min) {
min = item
} else {
l = i
}
}
if (l < r) return [l, r]
return [-1, -1]
};