【剑指offer】NC88 寻找第K大 [Go语言]

203 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情

题目

有一个整数数组,请你根据快速排序的思路,找出数组中第 k 大的数。

给定一个整数数组 a ,同时给定它的大小n和要找的 k ,请返回第 k 大的数(包括重复的元素,不用去重),保证答案存在。

示例1

输入:

[1,3,5,2,2],5,3

返回值:

2

示例2

输入:

[10,10,9,9,8,7,5,6,4,3,4,2],12,3

返回值:

9

说明:

去重后的第3大是8,但本题要求包含重复的元素,不用去重,所以输出9

思路

其实我们直接可以用快排,但是Top K想要考核的是堆排序,也就是我们这里从大到小的话,我们要创建一个最大堆。

我们所需要知道的是这样的一个规律

大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]

小顶堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]

其实就是反复进行交换、重建、交换的过程,直到整个序列有序

a.将无需序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;

b.将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端;

c.重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。

AC Code

func findKth( a []int ,  n int ,  K int ) int {
    if K>n || K<1{
        return -1
    }
(0)    buildMaxHeap(a,n)
    for i:=0;i<K;i++ {
(1)        adjustHeap(a,n-i,0)
(2)        a[0],a[n-i-1] = a[n-i-1],a[0]
    }
    return a[n-K]
}

func buildMaxHeap(a []int,length int){
(3)    for i:=length/2-1; i>=0; i-- {
(4)        adjustHeap(a,length,i)
    }
}

func adjustHeap(a []int,length int,pos int){
(5)    largeIndex := pos
(6)    if 2*pos+1 < length && a[2*pos + 1] > a[largeIndex]{
(7)        largeIndex = 2 * pos + 1
    }
(8)    if 2*pos+2 < length && a[2*pos + 2] > a[largeIndex]{
(9)        largeIndex = 2 * pos + 2
    }
(10)    if largeIndex != pos {
(11)        a[pos], a[largeIndex] = a[largeIndex], a[pos]
(12)        adjustHeap(a,length,largeIndex)
    }
}
  • (0) buildMaxHeap 进行创建最大堆
  • (1) 不断进行调整
  • (2) 调整完一次之后,将最大堆放在最后
  • (3) 从中间开始遍历,不断向左右建立堆
  • (4) 传入切片,长度,以及当前需要进行变换的下标
  • (5) 赋值当前的下标
  • (6) 如果当前的下标有左孩子的 并且 左孩子的值是比当前的父亲结点大的话
  • (7) 让最大的下标等于左孩子的下标
  • (8) 如果当前的下标有右孩子的 并且 右孩子的值比当前父亲节点大的话
  • (9) 就让最大的下标等于右孩子的下标
  • (10) 如果当前的最大下标发生改变的话,就是最大值的下标已经不是传进来的值了,而是左右孩子之一的值了
  • (11) 就进行交换
  • (12) 然后再进行调整,直到这个堆是最大堆