快速选择
用于求解 Kth Element 问题,也就是第 K 个元素的问题。
可以使用快速排序的 partition() 进行实现(略有区别)。需要先打乱数组,否则最坏情况下时间复杂度为 O(N2)。
在每执行一次的时候,比较基准值位置是否在 n-k 位置上,如果小于 n-k ,则第 k 个最大值在基准值的右边,我们只需递归基准值右边的子序列即可;如果大于 n-k ,则第 k 个最大值在基准值的做边,我们只需递归基准值左边的子序列即可;如果等于 n-k ,则第 k 个最大值就是基准值
堆
用于求解 TopK Elements 问题,也就是 K 个最小元素的问题。使用最小堆来实现 TopK 问题,最小堆使用大顶堆来实现,大顶堆的堆顶元素为当前堆的最大元素。实现过程:不断地往大顶堆中插入新元素,当堆中元素的数量大于 k 时,移除堆顶元素,也就是当前堆中最大的元素,剩下的元素都为当前添加过的元素中最小的 K 个元素。插入和移除堆顶元素的时间复杂度都为 log2N。
堆也可以用于求解 Kth Element 问题,得到了大小为 K 的最小堆之后,因为使用了大顶堆来实现,因此堆顶元素就是第 K 大的元素。
快速选择也可以求解 TopK Elements 问题,因为找到 Kth Element 之后,再遍历一次数组,所有小于等于 Kth Element 的元素都是 TopK Elements。
可以看到,快速选择和堆排序都可以求解 Kth Element 和 TopK Elements 问题。
215 数组中的第K个最大元素
Input: [3,2,1,5,6,4] and k = 2
Output: 5
在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
数组方法:
var findKthLargest = function (nums, k) {
return nums.sort((a, b) => b - a)[k - 1];
};
堆:
在这里插入代码片
快速选择:
var findKthLargest = function (nums, k) {
return quickSelect(nums, 0, nums.length - 1, nums.length - k);
};
function quickSelect(arr, left, right, k) {
if (left < right) {
let indexPivot = partition(arr, left, right);
if (indexPivot === k) return arr[k];
else if (indexPivot > k) return quickSelect(arr, left, indexPivot - 1, k);
else if (indexPivot < k) return quickSelect(arr, indexPivot + 1, right, k);
}
return arr[left];
}
function partition(arr, left, right) {
const pivot = arr[Math.floor((left + right) / 2)];
while (left < right) {
while (arr[left] < pivot) {
left++;
}
while (arr[right] > pivot) {
right--;
}
//为了让与主元相等的值多次换位,到其正确位置
if (left < right) {
[arr[left], arr[right]] = [arr[right], arr[left]];
}
//解决重复值导致的死循环
if (arr[left] === arr[right] && left !== right) {
left++;
}
}
return left
}