【leetcode算法--快排优化】215. 数组中的第K个最大元素

205 阅读1分钟

题目

给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。

请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。

提示

  • 1 <= k <= nums.length <= 105
  • -104 <= nums[i] <= 104

示例

输入: [3,2,1,5,6,4], k = 2

输出: 5

输入: [3,2,3,1,2,4,5,5,6], k = 4

输出: 4

思路

本题要求使用O(n)复杂度解决问题,所以不能直接采用快速排序然后去第k个。转换思路,快排其实是为了从小到大去排列元素,但是题目要求的是第k个,所以我们可以节省快排的一些步骤。

快速排序采用的是分而治之的思想,因此,我们先随机定义“标兵”,进行分隔两边数组(这里建议不要使用nums[0],容易不幸遇到时间复杂度最大n²的情况)

let index = Math.floor(nums.length/2)
let target = nums[index]

接着将数组以标兵target分为两边,这里建议使用splice方法而非slice方法,前者直接修改数组,不会再新建空间,而后者不会修改数组,但会造成不必要的空间浪费

nums.splice(index,1)
let maxArr = nums.filter(item=>item>target)
let minArr = nums.filter(item=>item<=target)

判断,如果分在target右边的数组长度刚好等于k-1,说明target刚好是第k个最大元素,直接返回即可。 如果target右边的数组长度>=k,说明第k个最大元素处于target右边的数组中,此时我们需要进行递归处理,传入maxArr,k值不变 如果target右边的数组长度<k-1,说明第k个最大元素处于target左边的数组中,此时我们需要进行递归处理,传入minArr,因为此时排除了maxArr和target,所以k应该改成k-1-maxArr.length

if(maxArr.length===k-1){
    return target
}else if(maxArr.length>=k){
    return findKthLargest(maxArr,k)
}else {
    return findKthLargest(minArr,k-1-maxArr.length)
}

全部代码

var findKthLargest = function(nums, k) {
    let index = Math.floor(nums.length/2)
    let target = nums[index]
    nums.splice(index,1)
    let maxArr = nums.filter(item=>item>target)
    let minArr = nums.filter(item=>item<=target)
    if(maxArr.length===k-1){
        return target
    }else if(maxArr.length>=k){
        return findKthLargest(maxArr,k)
    }else {
        return findKthLargest(minArr,k-1-maxArr.length)
    }
};