NC119 最小的K个数

最小的K个数

题目

输入整数数组 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
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题解-优先队列

堆排序算法

Java实现了堆结构,为了熟悉知识点这里直接使用。

先把所有数据放进堆种,默认排序时升序。
输出前k个数就是最小的K个数。


class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
        int len = arr.length;
        int [] res  = new int[k] ;
        if (k == 0 || len == 0) {
            return res;
        }
       Queue<Integer> q = new PriorityQueue<>();
       for(int num :arr){
           q.offer(num); //全部放进去
       }
       for(int i=0;i<k;i++){
         res[i] = q.poll(); //输出前k个数
       }
       return res;
    }
}

这样数组有多大,优先队列就需要有多大。如一次队就要排一次序,能不能较少排序的次数?

这里想到了另外一种思路,保持优先队列的大小就为K,里面存储最小的K个元素。
当队列中没有k个元素时直接入队,当队列中满了K个元素时,新元素与队列中最大的元素比较,所以这里队列应该采用降序排列,这样队头元素就是队列中的最大值。

class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
        if (k == 0 || arr.length == 0) {
            return new int[0];
        }
        //采用降序排列
        Queue<Integer> pq = new PriorityQueue<>((v1, v2) -> v2 - v1);
        for (int num: arr) {
			//当队列中没有k个元素时直接入队
            if (pq.size() < k) {
                pq.offer(num);
            } else if (num < pq.peek()) {//当队列中满了K个元素时,新元素与队列中最大的元素比较。比最大的小,最大的出队,小的入队
                pq.poll();
                pq.offer(num);
            }
        }
        // 返回堆中的元素
        int[] res = new int[pq.size()];
        int idx = 0;
        for(int num: pq) {
            res[idx++] = num;
        }
        return res;
    }
}

题解-快速排序

快排是选一个基准值,一趟之后基准值找到了自己的位置,左边部分是比基准值小的,右边部分是比基准值大的。

//主函数
public int[] getLeastNumbers(int[] arr, int k) {
   int len = arr.length;
   int [] res  = new int[k] ;
   if (k == 0 || len == 0) {
        return res;
   }
   sort(arr,0,len-1,k);
   for(int i=0;i<k;i++){
        res[i] = arr[i];
    }
    return res;
}

//sort排序
void sort(int[]nums,int left,int right,int k){
	if(left < right) { //如果基准点在最后一个元素,那么从下一轮递归中index+1>right了,用只有一个元素left==right判断就会出问题
	//找基准点的最终位置,返回索引值。
	int index = partiton(nums,left,right);
	if(index+1==k){//说明排序已经完成了,left及left之前就是我们求得最小的k个数
		return ;
	}
	if(index+1>k){//说明只需要对左半部分排序
		sort(nums,left,index-1,k);
	}else{//说明左边部分是需要的,不需要再排序了,直接排序右半边
		sort(nums,index+1,right,k);
	}
	}
}
//需要找到基准值的位置
int  partiton(int [] nums,int left,int right){
	int tmp = nums[left]; //基准值
	while(left<right){
		while(left<right && right>= tmp)--right; //找到了比基准值小的
		nums[left] = nums[right];
		while(left<right && left <= tmp)++left; //找到了比基准值大的
		nums[right] = nums[left];
	}//找到了基准值的位置
	nums[left] = tmp;
	return left;
}
posted @ 2022-01-04 10:08  rananie  阅读(41)  评论(0编辑  收藏  举报