如何找出排名前 500 的数?

作者: Java面试

题目描述

有 20 个数组,每个数组有 500 个元素,并且有序排列。如何在这 20*500 个数中找出前 500 的数?

解答思路

对于 TopK 问题,最常用的方法是使用堆排序。对本题而言,假设数组降序排列,可以采用以下方法:

首先建立大顶堆,堆的大小为数组的个数,即为 20,把每个数组最大的值存到堆中。

接着删除堆顶元素,保存到另一个大小为 500 的数组中,然后向大顶堆插入删除的元素所在数组的下一个元素。

重复上面的步骤,直到删除完第 500 个元素,也即找出了最大的前 500 个数。

为了在堆中取出一个数据后,能知道它是从哪个数组中取出的,从而可以从这个数组中取下一个值,可以把数组的指针存放到堆中,对这个指针提供比较大小的方法。

import lombok.Data;
import java.util.Arrays;
import java.util.PriorityQueue;
/**
 * @author https://github.com/yanglbme
 */
@Data
public class DataWithSource implements Comparable<DataWithSource> {
    /**
     * 数值
     */
    private int value;
    /**
     * 记录数值来源的数组
     */
    private int source;
    /**
     * 记录数值在数组中的索引
     */
    private int index;
    public DataWithSource(int value, int source, int index) {
        this.value = value;
        this.source = source;
        this.index = index;
    }
    /**
     *
     * 由于 PriorityQueue 使用小顶堆来实现,这里通过修改
     * 两个整数的比较逻辑来让 PriorityQueue 变成大顶堆
     */
    @Override
    public int compareTo(DataWithSource o) {
        return Integer.compare(o.getValue(), this.value);
    }
}
class Test {
    public static int[] getTop(int[][] data) {
        int rowSize = data.length;
        int columnSize = data[0].length;
        // 创建一个columnSize大小的数组,存放结果
        int[] result = new int[columnSize];
        PriorityQueue<DataWithSource> maxHeap = new PriorityQueue<>();
        for (int i = 0; i < rowSize; ++i) {
            // 将每个数组的最大一个元素放入堆中
            DataWithSource d = new DataWithSource(data[i][0], i, 0);
            maxHeap.add(d);
        }
        int num = 0;
        while (num < columnSize) {
            // 删除堆顶元素
            DataWithSource d = maxHeap.poll();
            result[num++] = d.getValue();
            if (num >= columnSize) {
                break;
            }
            d.setValue(data[d.getSource()][d.getIndex() + 1]);
            d.setIndex(d.getIndex() + 1);
            maxHeap.add(d);
        }
        return result;
    }
    public static void main(String[] args) {
        int[][] data = {
                ,
                ,
                ,
        };
        int[] top = getTop(data);
        System.out.println(Arrays.toString(top)); // [30, 29, 25, 20, 19]
    }
}

方法总结

求 TopK,不妨考虑一下堆排序?

更多推荐

更多
  • 自定义博客cnblogs样式的必备前端小知识js、jq ,自定义cnblogs样式的必备前端小知识——js、jq,JQ、JS相关小知识,,任意元素自动点击,添加子元素,删除、清空子元素,获取图片的src属性值,延迟执行,定时执行,JS打开新标签页,判断字符串中是否包含某个字符串,页面加载完后
    小菠萝测试笔记

  • 自定义博客cnblogs样式的必备前端小知识css ,自定义cnblogs样式的必备前端小知识——css,css样式相关小知识,,文字超出一行显示省略号,文字超出两行显示省略号,样式优先级关系,过渡样式,禁止元素点击事件,webkit内核美化滚动条,选取第n个元素,xt-overflow
    小菠萝测试笔记

  • net 获取存储过程返回值和output输出参数值 .net 获取存储过程返回值和Output输出参数值
    东北大亨

  • 入门学算法线性表链式存储达到麻将排序 先复习一些基本知识链式存储的特点:用一组任意的存储单元(可以连续,也可以不连续)存储线性表的数据元素。链式存储中每一个元素都是一个节点,每个节点中包含了数据域和指针域
    倒霉的菜鸟

  • 技术写作技巧分享:我是如何从写作小白成长为多平台优秀作者的? 技术写作技巧分享:我是如何从写作小白成长为多平台优秀的?为什么写作写什么怎么写推广总结“为学习而写”与“为刷声望而写”就是记个笔记有自己理解的知识点解析深入源码,探究原理从工作中总结推广的前提是高质量群,微信群分享找朋友,同事帮忙点赞找
  • webpack核心模块tapable源码解析 webpack核心模块tapable源码解析SyncHook的基本实现SyncBailHook的基本实现抽象重复代码抽象代码工厂其他Hook的实现总结参考资料子类SyncHook实现子类SyncBailHook的实现创建函数的方法创建代
  • webpack核心模块tapable用法解析 webpack核心模块tapable用法解析tapable是什么同步API异步API总结主要APISyncHookSyncBailHookSyncWaterfallHookSyncLoopHookAsyncParallelHookAsy
  • 手写一个webpack,看看AST怎么用 手写一个webpack,看看AST怎么用为什么要用webpack简单例子深入原理总结参考资料引入webpackwebpack把代码编译成了啥?自己实现一个webpack使用AST解析代码使用traverse遍历AST将import转换为
  • 速度提高几百倍,记一次数据结构在实际工作中的运用 速度提高几百倍,记一次数据结构在实际工作中的运用为什么没人做三层选项?解决方案总结1. 这可能是个伪需求2. 有性能问题两层查找树三层查找树写代码这就好了吗?还有一件事封装代码
  • 手写一个ReactRedux,玩转React的Context API 手写一个React-Redux,玩转React的Context API基本用法React的Context API手写Provider手写connect保证组件更新顺序总结参考资料先使用React.createContext创建一个con
  • 近期文章

    更多
    文章目录

      推荐作者

      更多