码迷,mamicode.com
首页 > 其他好文 > 详细

剑指offer:最小的K个数

时间:2020-04-18 22:49:10      阅读:54      评论:0      收藏:0      [点我收藏+]

标签:treeset   插入数据   java   numbers   划分数   pivot   star   查找   节点   

题意描述

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

解题思路

一、冒泡排序/选择排序

对数组进行排序,从数组中取出最小的k个数。不需要对数组全部排序,只需要找出前k个数即可。

二、快速排序

利用快速排序划分的思想,选择一个基数index,将基数左右划分为两部分。

  1. 位于index左边的数字都小于index对应的值,右边都大于index指向的值
  2. 所以,当index > k-1时,表示k个最小数字一定在index的左边,此时,只需要对index的左边进行划分即可
  3. index < k-1时,说明index及index左边数字还没能满足k个数字,需要继续对k右边进行划分
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        	ArrayList<Integer> list = new ArrayList<Integer>(k);
            if(input == null)	//输入校验
                return null;	
            if(k > input.length)
                return list;
            int low = 0;
            int high = input.length - 1;
            int index = partition(input,low,high);	//划分数组,并找到基数所在的位置
            while(index != k-1){	
                if(index > k-1){
                    high = index - 1;	//向左划分
                }else{
                    low = index + 1;	//向右划分
                }
                index = partition(input,low,high);	//继续划分数组,寻找基数所在位置
            }
           for(int i = 0; i < k; i++){
               list.add(input[i]);
           }
            return list;
        }
        //划分操作
        public int partition(int[] array,int start,int end){
            int pivot = array[start];	//数组首位作为基数
            //循环结束,将数组划分为两部分
            while(start < end){
                //从右向左查找,array[end] 《 pivot 的位置
                while(start < end && array[end] >= pivot) end--;
                //交换,放到左边
                array[start] = array[end];
                //从左向右查找,array[start] 》 pivot 的位置
                while(start < end && array[start] <= pivot) start++;
                //交换,放到右边
                array[end] = array[start];
            }
            //start最后指向的位置 就是 基数所在位置
            array[start] = pivot; 
            return start;	
        }

三、堆排序思想

  • 可以先创建一个大小为k的数据容器来存储最小的k个数字,从输入的n个整数中一个一个读入放入该容器中,如果容器中的数字少于k个,则返回null

  • 如果容器中已有k个数字,而数组中还有值未加入,此时就不能直接插入了,而需要替换容器中的值。按以下步骤进行插入:

    1. 先找到容器中的最大值
    2. 将待查入值和最大值比较,如果待查入值大于容器中的最大值,则直接舍弃这个待查入值即可;如果待查入值小于容器中的最小值,则用这个待查入值替换掉容器中的最大值
    3. 重复上述步骤,容器中最后就是整个数组的最小k个数字

对于这个容器的实现,我们可以使用最大堆的数据结构,最大堆中,根节点的值大于它的子树中的任意节点值。Java中的TreeSet类实现了红黑树的功能,它底层是通过TreeMap实现的,TreeSet中的数据会按照插入数据自动升序排列(按自然顺序)。因此我们直接将数据依次放入到TreeSet中,数组就会自动排序。

    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
             ArrayList<Integer> list = new ArrayList<>();
            if(input == null || k<=0 || k>input.length) return list;	//输入校验
            TreeSet<Integer> set = new TreeSet<>();
             for(int i=0;i<input.length;i++){
                 set.add(input[i]);	//数组元素添加入set
             }
            int i=0;
        	//取出前k个值
            for(Integer item : set){	
                if(i >= k) break;
                list.add(item);
                i++;
            }
            return list;
        }

剑指offer:最小的K个数

标签:treeset   插入数据   java   numbers   划分数   pivot   star   查找   节点   

原文地址:https://www.cnblogs.com/le-le/p/12728537.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!