[路飞]_程序员必刷力扣题: 面试题 16.16. 部分排序

332 阅读1分钟

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