场景:
解决Top K问题
例如:
输入: [3,2,1,5,6,4] 和 k = 2
输出: 5
解决方法:
此类问题一般都是通过一次快排或者大顶堆的方式解决,但是都有问题:
快排:对全数组进行了排序,如果要寻找的是第K个大的元素,那么其实我们并不关心从小到大排序后数组的第K位之后的数字;但是快排依然对这些数字进行了排序
大顶堆:虽然大顶堆的方法解决了不用考虑第K位之后的数字的问题,但是它依然需要关心第K位之前的数字,所以依然浪费了很多时间
问题分析
仔细想想Top K问题,其实我们本身只关心第K位上的数字。因为在数组中数字不重复的情况下,第K个最大的数字,必然位于第K-1位上。以例子中的[3,2,1,5,6,4]为例,假设寻找Top 4:
索引位 | 0 | 1 | 2 | 3 | 4 | 5 |
全排序结果 | 1 | 2 | 3 | 4 | 5 | 6 |
分区排序结果 | 2 | 1 | 3 | 6 | 4 | 5 |
无论是否进行全排序,第4个最大的值始终位于第2位上。所以寻找Top K的时候,我们其实只要把数组折腾成第K-1位的左边都小于第K-1位上的值;右边都是大于第K-1位上的值的样子后,那么第K-1位上的数字就是第K个最大的数字。
快速选择算法
快速选择的核心是利用快速排序的思想,通过取一个值作为pivot,对数组的一系列变换,最后使得pivot左侧的值都小于a[pivot], 右侧的值都大于a[pivot],且pivot位于数组第K-1位上,那么a[pivot]就是我们要找的Top K的值。
那么如果找到这个pivot并使得它恰好位于第K-1位上呢?这个只能靠蒙!!假设我们寻找Top 2步骤如下&