[路飞]_面试题 16.16. 部分排序

161 阅读2分钟

「这是我参与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]
};