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) 然后再进行调整,直到这个堆是最大堆