LeetCode 算法:部分排序

134 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第 21 天,点击查看活动详情

部分排序

原题地址

给定一个整数数组,编写一个函数,找出索引m和n,只要将索引区间[m,n]的元素排好序,整个数组就是有序的。注意:n-m 尽量最小,也就是说,找出符合条件的最短序列。函数返回值为[m,n],若不存在这样的m和n(例如整个数组是有序的),请返回[-1,-1]

示例1:

输入: [1,2,4,7,10,11,7,12,6,7,16,18,19]
输出: [3, 9]

示例2:

输入: [5,3,1,7,9]
输出: [0, 2]

提示:

  • 0 <= len(array) <= 1000000

思路分析

方法一

  1. 分析题目,需要得到一个下标数组,满足只要将 这个区间内的数据进行排序,那么整个数组就是有序的;
  2. 根据题目可以得知,要寻找的 m 值是存在一个在这个位置后有一个值比 array[m] 小的数值,而要寻找的 n 值是存在一个在这个位置前有一个值比 array[n] 大的数值;
  3. 那么,可以定义一个 mn,用来存储满足上述条件的所有下标;
  4. 由于 m 是正向循环找到的,n 是逆向循环找到的满足条件的值的集合,那么第一个即为我们想要的结果;
  5. 又因为若不存在时需要返回 -1,那么在寻找结束后,在 mn 中分别追加一个 -1,这样在找不到的时候有默认值;
  6. 最后返回 [m[0], n[0]] 即可。

方法二

  1. 题目要求默认值为 -1,那么定义 mn 的初始值时,就定义为 -1
  2. 若存在这样一个区间,那么一定位于数组的中间,所以可以从左右两边来寻找这样的数据;
  3. 所以进行两次循环,分别找出左右两边的第一个逆序数,也就是左边找一个右侧有比它小的数值,右边找一个左侧有比它大的数值。找到返回即可。

AC 代码

方法一

/**
 * @param {number[]} array
 * @return {number[]}
 */
var subSort = function(array) {
    let m = []
    let n = []
    for(let i = 0; i < array.length; i++) {
        for(let j = i + 1; j < array.length; j++) {
            if(array[j] < array[i]) {
                m.push(i)
                break
            }
        }
    }
    for(let i = array.length - 1; i >= 0; i--) {
        for(let j = i - 1; j >= 0; j--) {
            if(array[j] > array[i]) {
                n.push(i)
                break
            }
        }
    }
    m.push(-1)
    n.push(-1)
    return [m[0], n[0]]
};

结果:

  • 执行结果: 通过
  • 执行用时:5960 ms, 在所有 JavaScript 提交中击败了5.10%的用户
  • 内存消耗:57.5 MB, 在所有 JavaScript 提交中击败了8.16%的用户
  • 通过测试用例:38 / 38

方法二

/**
 * @param {number[]} array
 * @return {number[]}
 */
var subSort = function(array) {
    let m = -1
    let n = -1
    let max = Number.MIN_SAFE_INTEGER
    let min = Number.MAX_SAFE_INTEGER
    
    for(let i = 0; i < array.length; i++){
        if(array[i] >= max) max = array[i]
        else n = i
    }
    for(let i = array.length -1; i >= 0; i--){
        if(array[i] <= min) min = array[i]
        else m = i 
    }
    return [m, n]
};

结果:

  • 执行结果: 通过
  • 执行用时:60 ms, 在所有 JavaScript 提交中击败了96.94%的用户
  • 内存消耗:49.3 MB, 在所有 JavaScript 提交中击败了57.14%的用户
  • 通过测试用例:38 / 38

END