题目
给定整数数组 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)
}
};