29 最小的K个数

输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。

考点不是排序啊。如果输入的数据大于内存你怎么排序?

最小堆和最小堆的时间复杂度都是n*logn,但是最小堆在k个数之后添加的话需要调整堆,但是最大堆只要每次和顶端的比较就可以啦。另外最小堆不能解决数字动态增加的情况。

 

最大堆思路(todo)

1.取数组前K个元素建最大堆。

2将数组剩余元素一次与最大堆堆顶元素比较,如果比堆顶元素小,则删除堆顶元素,该元素入堆。

我们先来复习一下堆排序:

 

 1 import java.util.Arrays;
 2 
 3 /**
 4  * Created by chengxiao on 2016/12/17.
 5  * 堆排序demo
 6  */
 7 public class HeapSort {
 8     public static void main(String []args){
 9         int []arr = {9,8,7,6,5,4,3,2,1};
10         sort(arr);
11         System.out.println(Arrays.toString(arr));
12     }
13     public static void sort(int []arr){
14         //1.构建大顶堆
15         for(int i=arr.length/2-1;i>=0;i--){
16             //从第一个非叶子结点从下至上,从右至左调整结构
17             adjustHeap(arr,i,arr.length);
18         }
19         //2.调整堆结构+交换堆顶元素与末尾元素
20         for(int j=arr.length-1;j>0;j--){
21             swap(arr,0,j);//将堆顶元素与末尾元素进行交换
22             adjustHeap(arr,0,j);//重新对堆进行调整
23         }
24 
25     }
26 
27     /**
28      * 调整大顶堆(仅是调整过程,建立在大顶堆已构建的基础上)
29      * @param arr
30      * @param i
31      * @param length
32      */
33     public static void adjustHeap(int []arr,int i,int length){
34         int temp = arr[i];//先取出当前元素i
35         for(int k=i*2+1;k<length;k=k*2+1){//从i结点的左子结点开始,也就是2i+1处开始
36             if(k+1<length && arr[k]<arr[k+1]){//如果左子结点小于右子结点,k指向右子结点
37                 k++;
38             }
39             if(arr[k] >temp){//如果子节点大于父节点,将子节点值赋给父节点(不用进行交换)
40                 arr[i] = arr[k];
41                 i = k;
42             }else{
43                 break;
44             }
45         }
46         arr[i] = temp;//将temp值放到最终的位置
47     }
48 
49     /**
50      * 交换元素
51      * @param arr
52      * @param a
53      * @param b
54      */
55     public static void swap(int []arr,int a ,int b){
56         int temp=arr[a];
57         arr[a] = arr[b];
58         arr[b] = temp;
59     }
60 }
View Code

 

 1 /*
 2 *基于堆排序算法,构建最大堆。时间复杂度为O(nlogk)
 3 *如果用快速排序,时间复杂度为O(nlogn);
 4 *如果用冒泡排序,时间复杂度为O(n*k)
 5 */
 6 import java.util.ArrayList;
 7 public class Solution {
 8     public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
 9         ArrayList<Integer> list=new ArrayList<Integer>();
10         //检查输入的特殊情况
11         if(input==null || input.length<=0 || input.length<k){
12             return list;
13         }
14         //构建最大堆
15         for(int len=k/2-1; len>=0; len--){
16             adjustMaxHeapSort(input,len,k-1);
17         }
18         //从第k个元素开始分别与最大堆的最大值做比较,如果比最大值小,则替换并调整堆。
19         //最终堆里的就是最小的K个数。
20         int tmp;
21         for(int i=k; i<input.length; i++){
22             if(input[i]<input[0]){
23                 tmp=input[0];
24                 input[0]=input[i];
25                 input[i]=tmp;
26                 adjustMaxHeapSort(input,0,k-1);
27             }
28         }
29         for(int j=0; j<k; j++){
30             list.add(input[j]);
31         }
32         return list;
33     }
34      
35     public void adjustMaxHeapSort(int[] input, int pos, int length){
36         int temp;
37         int child;
38         for(temp=input[pos]; 2*pos+1<=length; pos=child){
39             child=2*pos+1;
40             if(child<length && input[child]<input[child+1]){
41                 child++;
42             }
43             if(input[child]>temp){
44                 input[pos]=input[child];
45             }else{
46                 break;
47             }
48         }
49         input[pos]=temp;
50     }
51 }

 

 

 

 

 

以下方法是用PriorityQueue类去实现的,也比较简洁

 1 import java.util.*;
 2 //用最大堆保存这k个数,每次只和堆顶比,如果比堆顶小,删除堆顶,新数入堆。
 3 public class Solution {
 4     public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
 5         ArrayList<Integer> res = new ArrayList<>();
 6         if (input.length < k)
 7             return res;
 8         //(n, m) -> m - n是lambda表达式,传入一个比较器,规则是大的反而小,所以得到一个大顶堆,默认的是一个小顶堆
 9         PriorityQueue<Integer> queue = new PriorityQueue<Integer>((n, m) -> m - n);
10         for (int num : input) {
11             queue.offer(num);
12             if (queue.size() > k)
13             queue.poll();
14         }
15         while (!queue.isEmpty()) 
16             res.add(queue.poll());
17         return res;
18         }
19 }

下面这个方法也可以采取,用了collections.sort()方法

 1 import java.util.ArrayList;
 2 import java.util.Collections;
 3 import java.util.List;
 4 public class Solution {
 5     public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
 6         List<Integer> list = new ArrayList<Integer>();
 7         ArrayList<Integer> res = new ArrayList<Integer>();
 8         if(input.length < k || input.length==0){
 9             return res;
10         }
11         for(int i=0;i<input.length;i++){
12             list.add(input[i]);
13         }
14         Collections.sort(list);
15         for(int i = 0;i<k;i++){
16             res.add(list.get(i));
17         }
18         return res;
19     }
20 }

可以将整型输入数组直接从小到大排序
java.util.Arrays.sort(input);

 输入可以借鉴一下(出自https://blog.csdn.net/chainiao_zhang/article/details/77740213)

 1 public class PopSortSolution {  
 2     public static void main(String[] args){  
 3         Scanner scanner = new Scanner(System.in);  
 4         System.out.println("请输入一个数组,以空格隔开:");  
 5         String str = scanner.nextLine();  
 6         System.out.println("请输入K的值:");  
 7         int k = scanner.nextInt();  
 8         scanner.close();                        //scanner使用后需要close,否则报警告。  
 9         String[] temp = str.split(" ");  
10         int[] array = new int[temp.length];  
11         for(int i = 0; i<temp.length; i++){  
12             array[i] = Integer.parseInt(temp[i]);  
13         }  
14         Solution solution = new Solution();  
15           
16         //GetLeastNumbet_Solution函数必须声明为static才能引用  
17         System.out.println("最小" + k +"个数是:" +solution.GetLeastNumbers_Solution(array, k));  
18     } 

 

posted @ 2019-06-26 11:29  淡如水94  阅读(166)  评论(0)    收藏  举报