剑指 Offer 40. 最小的k个数|手写大根堆

93 阅读1分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

一、题目描述

输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。

示例 1:

输入:arr = [3,2,1], k = 2 输出:[1,2] 或者 [2,1]

示例 2:

输入:arr = [0,1,2,1], k = 1 输出:[0]

二、思路分析

  1. 最小的k个数,可以初始建立一个k长度的大根堆,堆内一直维持k个元素,如果堆顶元素大于堆外元素,将堆外元素与堆顶元素互换,再堆化,时间复杂度为O(nlogk)。
  2. 函数包括一个建立大根堆的函数,和堆化的函数。
  3. 建立大根堆函数,从最后一个父节点开始,不断堆化。

三、AC 代码

func getLeastNumbers(arr []int, k int) (ans []int) {
    //建立k大小的堆
    heap := make([]int,k)
    for i := 0;i<k;i++ {
        heap[i] = arr[i]
    }
    if k == 0 {
        return ans
    }
    buildMaxHeap(heap,k)
    for i := k ;i < len(arr);i++ {
        if heap[0] > arr[i] {
            arr[i],heap[0] = heap[0],arr[i]
            maxHeapify(heap,0,k)
        }
    }
    return heap
}
//建立大根堆
func buildMaxHeap(arr []int,heapsize int) {
    for i := heapsize/2; i>=0 ;i-- {
        maxHeapify(arr,i,heapsize)
    }
}
//堆化
func maxHeapify(arr []int,i,heapsize int) {
    l,r := i*2+1,i*2+2
    largest := i
    if l < heapsize && arr[l] > arr[largest] {
        largest = l
    } 
    if r < heapsize && arr[r] > arr[largest] {
        largest = r
    }
    if largest != i {
        arr[largest],arr[i] = arr[i],arr[largest]
        maxHeapify(arr,largest,heapsize)
    }
}

四、总结

如果要找出前k个小元素,建立大根堆,这样堆可以维持k的大小。如果建立小根堆,则需要将所有元素放入堆内,时间消耗更多。