215. 数组中的第K个最大元素 🟨
题目
LeetCode 中等
给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。
请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。
示例 1:
输入: [3,2,1,5,6,4], k = 2
输出: 5
示例 2:
输入: [3,2,3,1,2,4,5,5,6], k = 4
输出: 4
题解
方法:快排的优化版
- 时间复杂度:O(n)
- 空间复杂度:O(logn)
js
function findKthLargest(nums, k) {
const quickSelect = (arr, targetIndex, start) => {
console.log('♻️ ', arr)
if (arr.length <= 1) return arr[0] //直接返回
let leftArr = []
let rightArr = []
const mid = Math.floor(arr.length / 2)
const midNum = arr[mid]
for (let i = 0; i < arr.length; i++) {
if (i === mid) continue
if (arr[i] > midNum) {
rightArr.push(arr[i])
} else {
leftArr.push(arr[i])
}
}
console.log(
'targetIndex',
targetIndex,
'startIndex',
start,
'midIndex',
mid,
'midNum',
midNum,
)
console.log('leftArr', leftArr, 'rightArr', rightArr)
if (leftArr.length + start === targetIndex) {
return midNum
} else if (leftArr.length + start > targetIndex) {
//继续在“小”组里找
return quickSelect(leftArr, targetIndex, start)
} else {
//继续在“大”组里找
return quickSelect(rightArr, targetIndex, leftArr.length + start + 1)
}
}
return quickSelect(nums, nums.length - k, 0)
}
const nums = [3,2,1,5,6,4],
k = 4
console.log('🌰', findKthLargest(nums, k))
执行结果
♻️ [3,2,1,5,6,4]
targetIndex 2 startIndex 0 midIndex 3 midNum 5
leftArr [3,2,1,4] rightArr [6]
♻️ [3,2,1,4]
targetIndex 2 startIndex 0 midIndex 2 midNum 1
leftArr [] rightArr [3,2,4]
♻️ [3,2,4]
targetIndex 2 startIndex 1 midIndex 1 midNum 2
leftArr [] rightArr [3,4]
♻️ [3,4]
targetIndex 2 startIndex 2 midIndex 1 midNum 4
leftArr [3] rightArr []
♻️ [3]
🌰 3
方法:堆排序
- 时间复杂度:O(nlogn)
- 空间复杂度:O(logn)
js
function findKthLargestHeap(nums, k) {
console.log([...nums])
let heapSize = nums.length
buildMaxHeap(nums, heapSize)
console.log('📌', [...nums])
for (let i = nums.length - 1; i >= nums.length - k + 1; i--) {
swap(nums, 0, i)
--heapSize
maxHeapify(nums, 0, heapSize)
console.log('📌', i, [...nums])
}
return nums[0]
// 自下而上构建一颗大顶堆
function buildMaxHeap(nums, heapSize) {
for (let i = Math.floor(heapSize / 2) - 1; i >= 0; i--) {
maxHeapify(nums, i, heapSize)
}
}
// 从左向右,自上而下的调整节点
function maxHeapify(nums, i, heapSize) {
let l = i * 2 + 1
let r = i * 2 + 2
let largest = i
if (l < heapSize && nums[l] > nums[largest]) {
largest = l
}
if (r < heapSize && nums[r] > nums[largest]) {
largest = r
}
if (largest !== i) {
swap(nums, i, largest)
maxHeapify(nums, largest, heapSize)
}
}
// 交换
function swap(arr, i, j) {
console.log('交换', arr[i], arr[j])
;[arr[i], arr[j]] = [arr[j], arr[i]]
}
}
const nums = [3, 2, 3, 1, 2, 4, 5, 5, 6],
k = 4
console.log('🌰', findKthLargestHeap(nums, k))
执行结果
[3,2,3,1,2,4,5,5,6]
交换 1 6
交换 3 5
交换 2 6
交换 2 5
交换 3 6
交换 3 5
📌 [6,5,5,3,2,4,3,2,1]
交换 6 1
交换 1 5
交换 1 3
交换 1 2
📌 8 [5,3,5,2,2,4,3,1,6]
交换 5 1
交换 1 5
交换 1 4
📌 7 [5,3,4,2,2,1,3,5,6]
交换 5 3
交换 3 4
📌 6 [4,3,3,2,2,1,5,5,6]
🌰 4