题目描述:
在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
今日学习:
1.复习快速排序
2.堆排序(大根堆、小根堆、建堆)
3.复习冒泡排序
题解:
1.用sort()
2.k次冒泡
3.快速排序
4.堆排序
//1.取巧
var findKthLargest = function(nums, k) {
nums.sort((a, b) => b - a)
return nums[k - 1]
};
//2.冒泡k次
var findKthLargest = function(nums, k) {
let count = k
while(count != 0) {
nums = bubble(nums)
count--
}
return nums[nums.length - k]
}
var bubble = function(nums) {
for(let i = 0; i < nums.length; i++) {
if(nums[i] > nums[i + 1]) {
[nums[i], nums[i + 1]] = [nums[i + 1], nums[i]]
}
}
return nums
}
//3.快速排序
const findKthLargest = (nums, k) => {
const n = nums.length;
const quick = (l, r) => {
if (l > r) return;
let random = Math.floor(Math.random() * (r - l + 1)) + l; // 随机选取一个index
swap(nums, random, r); // 将它和位置r的元素交换,让 nums[r] 作为 pivot 元素
//我们选定一个 pivot 元素,根据它进行 partition
//partition 找出一个位置:它左边的元素都比pivot小,右边的元素都比pivot大
//左边和右边的元素的是未排序的,但 pivotIndex 是确定下来的
let pivotIndex = partition(nums, l, r);
//我们希望这个 pivotIndex 正好是 n-k
//如果 n - k 小于 pivotIndex,则在 pivotIndex 的左边继续找
//如果 n - k 大于 pivotIndex,则在 pivotIndex 的右边继续找
if (n - k < pivotIndex) {
quick(l, pivotIndex - 1);
} else {
quick(pivotIndex + 1, r);
}
//n - k == pivotIndex ,此时 nums 数组被 n-k 分成两部分
//左边元素比 nums[n-k] 小,右边比 nums[n-k] 大,因此 nums[n-k] 就是第K大的元素
};
quick(0, n - 1); // 让n-k位置的左边都比 nums[n-k] 小,右边都比 nums[n-k] 大
return nums[n - k];
};
function partition(nums, left, right) {
let pivot = nums[right]; // 最右边的元素作为 pivot 元素
let pivotIndex = left; // pivotIndex 初始为 left
for (let i = left; i < right; i++) { // 逐个考察元素,和 pivot 比较
if (nums[i] < pivot) { // 如果当前元素比 pivot 小
swap(nums, i, pivotIndex); // 将它交换到 pivotIndex 的位置
pivotIndex++;
}
} // 循环结束时,pivotIndex左边都是比pivot小的
swap(nums, right, pivotIndex); // pivotIndex和right交换,更新pivot元素
return pivotIndex; // 返回 pivotIndex 下标
}
function swap(nums, p, q) {
const temp = nums[p];
nums[p] = nums[q];
nums[q] = temp;
}
//4.堆排序
let findKthLargest = function(nums, k) {
// 从 nums 中取出前 k 个数,构建一个小顶堆
let heap = [,], i = 0
while(i < k) {
heap.push(nums[i++])
}
buildHeap(heap, k)
// 从 k 位开始遍历数组
for(let i = k; i < nums.length; i++) {
if(heap[1] < nums[i]) {
// 替换并堆化
heap[1] = nums[i]
heapify(heap, k, 1)
}
}
// 返回堆顶元素
return heap[1]
};
// 原地建堆,从后往前,自上而下式建小顶堆
let buildHeap = (arr, k) => {
if(k === 1) return
// 从最后一个非叶子节点开始,自上而下式堆化
for(let i = Math.floor(k/2); i>=1 ; i--) {
heapify(arr, k, i)
}
}
// 堆化
let heapify = (arr, k, i) => {
// 自上而下式堆化
while(true) {
let minIndex = i
if(2*i <= k && arr[2*i] < arr[i]) {
minIndex = 2*i
}
if(2*i+1 <= k && arr[2*i+1] < arr[minIndex]) {
minIndex = 2*i+1
}
if(minIndex !== i) {
swap(arr, i, minIndex)
i = minIndex
} else {
break
}
}
}
// 交换
let swap = (arr, i , j) => {
let temp = arr[i]
arr[i] = arr[j]
arr[j] = temp
}