面试题:从10亿个随机整数中,找出前1000个最大数

题目描述

从10亿个随机整数中,找出前1000个最大数,要求以最小的时间复杂度及空间复杂度实现该需求。

解题思路

这道题的解决思路是将无序整数排列为有序序列,升序或降序,从中取出前1000个最大数。适用的排序算法包括:

  • 插入排序、选择排序、冒泡排序、快速排序等,时间复杂度:

  • 堆排序、归并排序,时间复杂度:

本题需要实现的是找出前1000个最大数,空间上可以只做1000条最大目标数组,其他数据与目标数组进行比较,如果比较值小于目标数组最小值,则抛弃。否则将最小值替换为比较值,并使用排序算法完成数据排序。本题采用算法为构建一个大小为1000的小顶堆排序(读者可自行查阅堆排序相关资料)。空间复杂度:

。排序算法及时间复杂度参考见下图:

排序方法

时间复杂度(平均)

时间复杂度(最坏)

时间复杂度(最好)

空间复杂度

稳定性

复杂性

直接插入排序

O(n2)

O(n2)

O(n)

O(1)

稳定

简单

希尔排序

O(nlog2n)

O(n2)

O(n1.3)

O(1)

不稳定

较复杂

直接选择排序

O(n2)

O(n2)

O(n2)

O(1)

不稳定

简单

堆排序

O(nlog2n)

O(nlog2n)

O(nlog2n)

O(1)

不稳定

较复杂

冒泡排序

O(n2)

O(n2)

O(n)

O(1)

稳定

简单

快速排序

O(nlog2n)

O(n2)

O(nlog2n)

O(nlog2n)

不稳定

较复杂

归并排序

O(nlog2n)

O(nlog2n)

O(nlog2n)

O(n)

稳定

较复杂

基数排序

O(d(n+r))

O(d(n+r))

O(d(n+r))

O(n+r)

稳定

较复杂

堆排序的特性

  1. 堆是一颗完整二叉树,除了最后一层节点不是满的,其余每一层从左到右都是满的。
  2. 堆中的每个节点的整数值,都小于或等于这个节点的子节点的整数。
  3. 对使用数组实现二叉树,满足以下条件公式:
    • 节点的左子节点的index为:2*index + 1
    • 节点的右子节点的index为:2*index + 2
    • 节点的父节点的index为:(index-1)/2

面试题:从10亿个随机整数中,找出前1000个最大数

堆-完全二叉树

代码实现

说明:直接通过内存生成10亿条数据,容易产生堆内存溢出,可分批加载(如每次10000条)并完成小顶堆排序,并输出1000条数据。本例为方便测试验证,仅测试100条数据,查找最大的10条。

public class HeapSortTest {
    //10亿数字.
    public static int LEN = 100;
    //TOP 1000
    public static int TOP = 10 ;
    //10亿数字数组
    public static int arr[] = new int[LEN] ;
    //TOP1000的小顶堆数组
    public static int res[] = new int[TOP] ;

    public static void main(String[] args) {
        for (int i = 0; i < LEN; i++) {
            arr[i] = new Random().nextInt(1000);
        }
        //构建初始堆
        for (int i = 0; i < TOP; i++) {
            res[i] = arr[i];
        }
        //构建小顶堆
        long start = System.currentTimeMillis() ;
        buildMinHeap(res);
        for (int i = TOP; i < LEN; i++) {
            if (arr[i] > res[0]) {
                res[0] = arr[i];
                minHeap(res, 0);
            }
        }
        System.out.println(LEN + "个数,求Top" + TOP + ",耗时" + (System.currentTimeMillis() - start) + "毫秒");
        System.out.println(Arrays.toString(res));

    }
        /**
         * 自底层向上构建一个小顶堆
         */
        public static int[] buildMinHeap(int[] arr) {
        for(int i= arr.length/2 -1; i>=0; i--) {
            minHeap(arr, i) ;
        }
        return arr ;
    }

    /**
     * 根据插入的值,生成小顶堆
     */
    private static void minHeap(int[] arr, int current) {
        int left = current*2 + 1, right = current*2 + 2, min = current ;
        if(left < arr.length && arr[left] < arr[min]) {
            min = left;
        } else if(right < arr.length && arr[right] < arr[min]) {
            min = right ;
        }
        if(min != current) {
            int tmp = arr[min] ;
            arr[min] = arr[current] ;
            arr[current] = tmp ;
            minHeap(arr, min);
        }
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值