最小的K个数

题目描述

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

思路一

最容易想到的思路就是将输入的n个整数进行从小到大的排序,然后选出前K个数就是最小的K个数,这里选用的是最简单的冒泡排序的算法

时间复杂度:o(n^2)

import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        
        ArrayList<Integer> list =  new ArrayList<Integer>();
        int len = input.length;
        if(k > len) return list;
        int temp = 0;
        for(int i = 0; i < len -1; i++){//控制轮回的次数 len - 1次
            for(int j = 0; j < len - 1 - i;j++){
                //这里要减i的原因是内层两两比较的边界会随着轮回的次数而减少
                //第一次轮回已经找到了最大的数,冒泡到了最后,那么下一次就少一个数了
                //这里需要len -1是为了防止后面input[j+1]溢出
                if(input[j] > input[j + 1]){
                    temp = input[j];
                    input[j] = input[j+1];
                    input[j+1] = temp;
                }
            }
        }
        for(int i = 0; i < k; i++){
            list.add(input[i]);
        }
        
       return list;
    }
}

总结

  • 测试用例的周全性:当k的值大于数组的长度

    if(k > len) return list;
    
  • 冒泡排序的边界问题,笔者对冒泡还不是很熟悉,所以又仔细分析了一波冒泡,熟悉的可以略过这部分😶

    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.Map;
    
    public class Test10 {
    
        public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
            for(int i = 0; i < input.length; i++){
    
                System.out.print(input[i]+"=>");
            }
            System.out.println("\n");
            ArrayList<Integer> list =  new ArrayList<Integer>();
            int len = input.length;
            if(k > len) return list;
            int temp = 0;
            for(int i = 0; i < len -1; i++){
                System.out.println("===========外层循环=============:"+"i="+i);
                for(int h = 0; h < input.length; h++){
    
                    System.out.print(input[h]+"=>");
                }
                System.out.println("\n");
                for(int j = 0; j < len - 1 - i;j++){
                    System.out.println("内层循环:"+"j="+j);
                    System.out.println("input[j]:"+input[j]);
                    System.out.println("input[j + 1]:"+input[j + 1]);
                    if(input[j] > input[j + 1]){
                        temp = input[j];
                        input[j] = input[j+1];
                        input[j+1] = temp;
                    }
                }
            }
            for(int i = 0; i < k; i++){
                list.add(input[i]);
            }
    
            return list;
        }
    
    
        public static void main(String[] args){
            Test10 test10 = new Test10();
            int[] arr = {4,2,6,1,5};
            ArrayList<Integer> list = test10.GetLeastNumbers_Solution(arr,3);
    
            for(int i = 0; i < list.size(); i++){
    
                System.out.println(list.get(i));
            }
        }
    }
    
    
    
    4=>2=>6=>1=>5=>
    
    ===========外层循环=============:i=0
    4=>2=>6=>1=>5=>
    
    内层循环:j=0
    input[j]:4
    input[j + 1]:2
    内层循环:j=1
    input[j]:4
    input[j + 1]:6
    内层循环:j=2
    input[j]:6
    input[j + 1]:1
    内层循环:j=3
    input[j]:6
    input[j + 1]:5
    ===========外层循环=============:i=1
    2=>4=>1=>5=>6=>
    
    内层循环:j=0
    input[j]:2
    input[j + 1]:4
    内层循环:j=1
    input[j]:4
    input[j + 1]:1
    内层循环:j=2
    input[j]:4
    input[j + 1]:5
    ===========外层循环=============:i=2
    2=>1=>4=>5=>6=>
    
    内层循环:j=0
    input[j]:2
    input[j + 1]:1
    内层循环:j=1
    input[j]:2
    input[j + 1]:4
    ===========外层循环=============:i=3
    1=>2=>4=>5=>6=>
    
    内层循环:j=0
    input[j]:1
    input[j + 1]:2
    1
    2
    4
    
    Process finished with exit code 0
    
    

    基于堆的实现

  • 创建容器:首先创建一个大小为k的数据容器用来存储最小的k个数字

  • 读取数据:依次读入n个数,每读一个数之前判断当前容器中的数字个数是否小于k,如果小于,放入容器继续读;如果等于k,找出容器中的最大值和当前读取的数进行比较,如果当前数小就放入容器,如果当前数大就放弃继续读

    (这里每次都需要找到当前容器中的最大值,所以我们考虑用最大堆实现)


    public ArrayList<Integer> GetLeastNumbers_Solution1(int[] input, int k) {
        ArrayList<Integer> result = new ArrayList<Integer>();
        int length = input.length;
        if(k > length || k == 0){
            return result;
        }
        //通过优先队列构建一个最大堆
        PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(k, new Comparator<Integer>() {

            @Override
            public int compare(Integer o1, Integer o2) {
                //重新compare方法,实行降序排列 => 最大堆
                return o2.compareTo(o1);
            }
        });
        //依次向容器中装入length个数
        for (int i = 0; i < length; i++) {
            //如果容器中的数小于k,那么就装入
            if (maxHeap.size() != k) {
                //Inserts the specified element into this priority queue.
                maxHeap.offer(input[i]);
                //如果容器中的数等于k,那么就需要比较即将装入的数和容器中最大值(根节点)的大小
            } else if (maxHeap.peek() > input[i]) {
                //remove and return the head of the queue
                Integer temp = maxHeap.poll();
                temp = null;
                //将即将装入的数装进容器堆中
                maxHeap.offer(input[i]);
            }
        }
        for (Integer integer : maxHeap) {
            result.add(integer);
        }
        return result;
    }

参考

剑指Offer-31-最小的K个数

posted @ 2019-03-05 17:11  crr121  阅读(131)  评论(0编辑  收藏  举报