JZ29 最小的K个数
最小的K个数
给定一个数组,找出其中最小的K个数。例如数组元素是4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4。如果K>数组的长度,那么返回一个空的数组
方法1:堆
思路和算法
我们用一个大根堆实时维护数组的前 k 小值。首先将前 k 个数插入大根堆中,随后从第 k+1个数开始遍历,如果当前遍历到的数比大根堆的堆顶的数要小,就把堆顶的数弹出,再插入当前遍历到的数。最后将大根堆里的数存入数组返回即可。在下面的代码中,由于 C++ 语言中的堆(即优先队列)为大根堆,我们可以这么做。而 Python 语言中的堆为小根堆,因此我们要对数组中所有的数取其相反数,才能使用小根堆维护前 k 小值。
方法2、用快排最高效解决 TopK 问题:O(N)
注意找前 K 大/前 K 小问题不需要对整个数组进行 O(NlogN)的排序!
例如本题,直接通过快排切分排好第 K 小的数(下标为 K-1),那么它左边的数就是比它小的另外 K-1 个数啦~
func GetLeastNumbers_Solution(input []int, k int) []int { // write code here res := make([]int, 0) if k == 0 || len(input) == 0 { return res } quickSelect(input, 0, len(input)-1, k) return input[:k] } func quickSelect(nums []int, low, high, k int) { if low >= high { return } pivotIndex := partition(nums, low, high) if k-1 == pivotIndex { return } else if k-1 < pivotIndex { quickSelect(nums, low, pivotIndex-1, k) } else { quickSelect(nums, pivotIndex+1, high, k) } } func partition(nums []int, low, high int) int { pivot := nums[high] // 可以随机,可以固定 i := low for j := low; j < high; j++ {// 双指针,i指向小于等于pivot的位置,j指向大于pivot的位置,然后交换位置 if nums[j] <= pivot { nums[i], nums[j] = nums[j], nums[i] i++ } } nums[i], nums[high] = nums[high], nums[i] // 把锚点放在左右的中间 return i }