原文发表于:

 

     top-K问题是很常见的。在T公司的两次面试中,都遇到了这个问题,在S公司的面试中,也遇到了这个问题。本文来具体聊一下top-K问题:有N个整数,求出最大的K个值,内存无法容纳这N个整数

 

      一眼便知道是海量数据问题,直接用堆就行了,确实如此。但是,我觉得这样太经验主义了,为什么要用堆呢?为什么不用其它的数据结构呢?

 

     我们来简化一下上面的题目:

     有N个整数,求出最大的K个值,其中K=1,内存可以容纳这N个整数。

 

     求最大值,就跟擂台赛差不多,姑且认为最开始上台的人是最强的,然后第二个上场,败者被淘汰,胜者继续留在台上。最后,留在台上的人就是最强的。

 

       求最大值代码如下,简单得很:

package main

import "fmt"

func findMax(a []int) int {  
    max := a[0]  // 假设a的长度大于0
    for _, v := range a {
        if v > max { // 擂台赛,新来的v胜利了,要留在台上
            max = v
        }
    }
    
    return max
}

func main() {
    a := []int{3, 4, 2, 1, 9, 5, -1, 18, 6}
    fmt.Println(findMax(a))
}

 

      下面,我们来看top-K问题,  很显然,可以采用类似的思路:随便找出K个值,认为它们是最大的K个值,然后遍历其它元素v,如果v比K个值的最小值还小,则v没有资格成为最大的K个值;如果v比K个值的最小元素要大,则这个最小值没有资格成为最大K个值中的一员,需要被v替代,原理和擂台赛相似。

 

      那么,怎么找出K个元素的最小值呢?显然,小顶堆是非常适合的。我们来看下小顶堆的定义:

      (1)小顶堆每个结点的值,不小于其父结点的值;

      (2)小顶堆是一棵完全二叉树。

 

       小顶堆的数据结构如下:

 

      怎么去实现一个堆呢?堆是一颗完全二叉树,非常紧凑,所以用数组来存储是比较方便的。关于堆的代码,本文就不再单独列出来了。

     在笔试面试的时候,如果能写出堆的代码,当然很好。如果实在写不出来,也要跟面试官讲清楚自己的思路,毕竟思路是非常重要的。

 

      堆是一种很美的数据结构,堆的另外一个应用是堆排序,有兴趣的朋友可以查阅相关资料,进行深入了解。


本文转载:CSDN博客