Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
一、题目描述
给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。
输入:[3,2,1,5,6,4] k=2 输出:5
输入:[3,2,3,1,2,4,5,5,6] k=4 输出:4
二、思路分析
- 第K个最大元素,可以基于大根堆实现,删除前k-1个元素,堆顶为第k个最大元素
- 面试倾向于考察堆的建立、调整、删除,所以应该手写实现一个堆。
- 做题时经常忘记删除元素时,heapsize应该减一。用数组构造二叉树结构中,当前节点的左子节点下标应该是
i*2+1,右子节点下标为i*2+2 - 建堆时间复杂度为
O(n),删除的时间复杂度为O(klogn),总时间复杂度为O(n+klogn)即O(nlogn) - 更优时间复杂度方法可以考虑基于快排的快速选择算法,可以查看上一篇博文快速选择算法
三、AC 代码
func findKthLargest(nums []int, k int) int {
heapsize := len(nums)
buildMaxHeap(nums,heapsize)
//将k-1个大元素替换堆外元素,再进行调整
for i := len(nums) - 1; i >=len(nums)-k+1;i-- {
nums[0],nums[i] = nums[i],nums[0]
heapsize--
maxHeapify(nums,0,heapsize)
}
//返回第k大元素
return nums[0]
}
//构造原数组为大根堆
func buildMaxHeap(nums []int,heapsize int ){
for i := heapsize / 2 ; i >= 0; i-- {
maxHeapify(nums,i,heapsize)
}
}
//堆调整
func maxHeapify(nums []int,i int,heapsize int) {
//左右子节点
l,r := i*2 +1 ,i*2+2
largest := i
//左子节点大于当前节点
if l < heapsize && nums[l] > nums[largest] {
largest = l
}
//右子节点大于当前节点
if r < heapsize && nums[r] > nums[largest] {
largest = r
}
if i != largest {
nums[largest],nums[i] = nums[i],nums[largest]
maxHeapify(nums,largest,heapsize)
}
}
四、总结
第K个最大元素,是比较高频率的题目,常用的方法有基于快排的快速选择以及基于堆排序的选择,熟悉快排的性质,可以在快排过程中选择出第k大元素。大根堆替换前k-1个元素到堆顶进行调整,小根堆则位置k个元素在堆里,堆顶的最小元素即为第k大元素。