春招打卡|第k个最大元素|基于堆排序|go实现

255 阅读2分钟

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

二、思路分析

  1. 第K个最大元素,可以基于大根堆实现,删除前k-1个元素,堆顶为第k个最大元素
  2. 面试倾向于考察堆的建立、调整、删除,所以应该手写实现一个堆。
  3. 做题时经常忘记删除元素时,heapsize应该减一。用数组构造二叉树结构中,当前节点的左子节点下标应该是i*2+1,右子节点下标为i*2+2
  4. 建堆时间复杂度为O(n),删除的时间复杂度为O(klogn),总时间复杂度为O(n+klogn)O(nlogn)
  5. 更优时间复杂度方法可以考虑基于快排的快速选择算法,可以查看上一篇博文快速选择算法

三、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大元素。