输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
示例 1:
输入:arr = [3,2,1], k = 2
输出:[1,2] 或者 [2,1]
示例 2:
输入:arr = [0,1,2,1], k = 1
输出:[0]
限制:
0 <= k <= arr.length <= 10000
0 <= arr[i] <= 10000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
堆
维持一个容量为k大根堆,将数组剩下的元素依次与堆顶比较,比堆顶小就加入堆。
/**
* @param {number[]} arr
* @param {number} k
* @return {number[]}
*/
var makeHeap=function(arr,length){
let i=Math.floor(length/2)-1;
while(i>=0){
let j=(i+1)*2-1,index=i,ai=arr[i];
while(j<length){
if(j+1<length&&arr[j+1]>arr[j]){
j++;
}
if(arr[j]>ai){
arr[index]=arr[j];
index=j;
j=(j+1)*2-1;
}else{
break;
}
}
arr[index]=ai;
i--;
}
}
var siftDown=function(arr,length){
let j=1,index=0,ai=arr[0];
while(j<length){
if(j+1<length&&arr[j+1]>arr[j]){
j++;
}
if(arr[j]>ai){
arr[index]=arr[j];
index=j;
j=(j+1)*2-1;
}else{
break;
}
}
arr[index]=ai;
}
var getLeastNumbers = function(arr, k) {
let length=arr.length;
makeHeap(arr,k);
for(let i=k;i<length;i++){
if(arr[i]<arr[0]){
arr[0]=arr[i];
siftDown(arr,k);
}
}
return arr.slice(0,k)
};
时间复杂度O(nlogk)
快排变形
快排每次划分的中间值都不会再移动位置了,所以索引为K的即为第k+1小的元素,据此可以比较划分值得位置与K,调整下一次划分得区间直到划分值的索引为K .
class Solution:
def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:
def partition(arr,left,right):
if left>=right:
return left
x=arr[left]
i,j=left,right
while i<j:
while i<j and arr[j]>=x:
j=j-1
arr[i]=arr[j]
while i<j and arr[i]<x:
i=i+1
arr[j]=arr[i]
arr[i]=x
return i
left=0
right=len(arr)-1
index=-1
while index!=k:
index=partition(arr,left,right)
if index<k:
left=index+1
else:
right=index-1
return arr[0:k]
注意:以上代码都改变了原数组,如果不能原地修改,就把数组复制一下就好