剑指offer之:40最小的k个数

剑指offer之:40最小的k个数

题目描述:

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

解法一:

把输入的n个整数进行排序,排序后位于前面的k个数就是最小的k个数。时间复杂度O(nlogn)(快排)。此方法只适用于我们可以修改输入的数组时。基于Partition。

解法二:

不能修改输入的数组时,我们可以是用最大堆。时间复杂度是O(nlogk)。适合处理海量数据。
我们首先创建一个大小为k的数据容器来存储最小的k个数字,接下来每次从输入的n个整数中读入一个数字。如果容器中已有的数字少于k个,则读取时直接存入容器;如果容器中已有k个数字了,就说明容器已满,此时我们就不能再插入新的数字而只能替换已有的数字。找出已有的k个数中的最大值。然后拿这次待插入的数和最大值相比。如果待插入的数比已有的最大值小,则用这个数替换当前已有的最大值;如果待插入的数比已有的最大值还大,就可以抛弃。
因此,容器满了以后有3件事要做:1.在k个整数中找到最大数;2.有可能在这个容器中删除最大数;3.有可能要插入一个新的数字。如果使用一棵二叉树来实现这个容器,可以再O(logk)时间内实现这3步。故,对于n个输入的数字而言,总的时间效率就是O(nlogk)。
最大堆:根节点得值总是大于它的子树中任意节点的值。于是我们可以在O(1)时间内得到已有的k个数字中的最大值,但是需要O(logk)时间完成删除以及插入操作。

代码块:
import java.util.ArrayList;
import java.util.Comparator;
import java.util.PriorityQueue;

public class Solution {

     public static ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
         ArrayList<Integer> rst = new ArrayList<Integer>();
         if(input.length < k || k <= 0  ){
                return rst;
         }
         PriorityQueue<Integer> maxHeap = new PriorityQueue<>(k, new Comparator<Integer>() {
             @Override
             public int compare(Integer o1, Integer o2) {
                 return o2.compareTo(o1);
             }
         });
         for(int i = 0; i < input.length; i++){
             if (maxHeap.size() < k){
                 maxHeap.offer(input[i]);
             }else if(maxHeap.peek() > input[i]){
                 Integer temp = maxHeap.poll();
                 temp = null;
                 maxHeap.offer(input[i]);
             }
         }
         for(Integer integer : maxHeap){
             rst.add(integer);
         }
         return rst;

     }

    public static void main(String[] args) {
        int input[] = {4,5,1,6,2,7,3,8};
        int k = 4;
        ArrayList a = (ArrayList) GetLeastNumbers_Solution(input, k);
        System.out.println(a);
    }
}

解法三:

最大堆代码比较困难,可以采用红黑树(确保树在一定程度上是平衡的)来实现我们的容器。在STL(standard Template Library标准模板库:1.算法2.容器3.函数4.迭代器)中,set和multiset都是基于红黑树实现的。

代码块
import java.util.ArrayList;
import java.util.Iterator;
import java.util.TreeSet;

public class Solution2redblacktree {
    public static ArrayList GetLeastNumbers(int[] input, int k){
        ArrayList<Integer> list = new ArrayList<Integer>();
        if(input.length <=0 || k <=0 || input.length < k){
            return list;
        }
        TreeSet<Integer> kSet = new TreeSet<Integer>();
        for(int i = 0 ; i < input.length; i++){
            if(kSet.size() < k){
                kSet.add(input[i]);
            }else if(input[i] < kSet.last()){
                kSet.remove(kSet.last());
                kSet.add(input[i]);
            }
        }
        Iterator<Integer> iterator = kSet.iterator();
        while(iterator.hasNext()){//不是if
            list.add(iterator.next());
        }
        return list;

    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值