「这是我参与2022首次更文挑战的第2天,活动详情查看: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]
题解
思路
两次遍历数组; 从左到右保存数组出现的最大值,得到数组left 从右到左保存数组出现的最小值,得到数组right 枚举left,right; 从左到右,left[k] !== right[k] ;k可能是左边界 从右到左,left[k] !== right[k] ;k可能是右边界
如果左边界 = 0;右边界 = len-1;排序好的数组 返回左右边界;
演示
如果数组nums = [1,2,4,7,10,11,7,12,6,7,16,18,19]
从左到右,保留数组最大值left = [1, 2, 4, 7, 10, 11, 11, 12, 12, 12, 16, 18, 19]
从右到左,保留数组最小值right = [1, 2, 4, 6, 6, 6, 6, 6, 6, 7, 16, 18, 19]
观察,当left,right不同时,正好时需要寻找的左右区间;
巧合吗?
分析,对于数组left\right任意位置k,在left数组中,k表示当前数组最小值,从左到右不是递增数组,如果在right相同的位置值也相同,表示在right数组[k,right.length]区间没有比k再小的元素了。从而证明从[0,k]区间原数组是持续递增的
代码
/**
* @param {number[]} array
* @return {number[]}
*/
var subSort = function(array) {
const len = array.length;
if(len < 2) return [-1,-1]
let left = [];
left[0] = array[0]
for(let i = 1 ; i < len ; i++){
left[i] = Math.max(left[i-1],array[i])
}
let right = [];
right[len-1] = array[len-1];
for(let i = len -2 ; i >=0 ; i--){
right[i] = Math.min(array[i],right[i+1])
}
let l = 0;
for(let i = 0 ; i < len ; i++){
if(left[i] !== right[i]){
l = i
break
}
}
let r = len-1
for(let i = len - 1 ; i >=0 ; i--){
if(left[i] !== right[i]){
r = i
break
}
}
if(l === 0 && r === len-1) return [-1,-1]
return [l,r]
};