当前位置: 首页 > news >正文

面试题:在1亿个数据中取前10个最大的数据(Java实现)

处理大规模数据时获取前N个最大/最小元素是一个常见问题,以下是几种Java实现方案:

1. 使用优先队列(最小堆) - 最优方案

import java.util.PriorityQueue;public class Top10Elements {public static int[] findTop10(int[] nums) {// 使用最小堆,容量保持为10PriorityQueue<Integer> minHeap = new PriorityQueue<>(10);for (int num : nums) {if (minHeap.size() < 10) {minHeap.offer(num);} else if (num > minHeap.peek()) {minHeap.poll();  // 移除堆顶最小元素minHeap.offer(num);  // 插入新元素}}// 将结果转为数组int[] result = new int[10];for (int i = 9; i >= 0; i--) {result[i] = minHeap.poll();}return result;}
}

时间复杂度:O(n log k),其中n是1亿,k是10。这种方法只需要O(n)的遍历时间和O(log k)的堆操作时间。

空间复杂度:O(k),只需要维护大小为10的堆。

2. 使用快速选择算法 - 适合内存有限情况

import java.util.Arrays;public class Top10Elements {public static int[] findTop10(int[] nums) {quickSelect(nums, 0, nums.length - 1, 10);// 此时前10个元素是最大的,但不一定有序int[] result = Arrays.copyOf(nums, 10);Arrays.sort(result);  // 如果需要有序结果// 反转数组使从大到小排序for (int i = 0; i < 5; i++) {int temp = result[i];result[i] = result[9 - i];result[9 - i] = temp;}return result;}private static void quickSelect(int[] nums, int left, int right, int k) {if (left >= right) return;int pivot = partition(nums, left, right);if (pivot == k) {return;} else if (pivot < k) {quickSelect(nums, pivot + 1, right, k);} else {quickSelect(nums, left, pivot - 1, k);}}private static int partition(int[] nums, int left, int right) {int pivot = nums[right];int i = left;for (int j = left; j < right; j++) {if (nums[j] >= pivot) {  // 降序排列swap(nums, i, j);i++;}}swap(nums, i, right);return i;}private static void swap(int[] nums, int i, int j) {int temp = nums[i];nums[i] = nums[j];nums[j] = temp;}
}

时间复杂度:平均O(n),最坏O(n^2),但实际应用中表现良好。

3. 并行处理方案(针对超大数据集)

import java.util.Arrays;
import java.util.PriorityQueue;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;public class ParallelTop10 {private static final int THRESHOLD = 1_000_000;public static int[] findTop10(int[] nums) {ForkJoinPool pool = new ForkJoinPool();return pool.invoke(new TopKTask(nums, 0, nums.length - 1, 10));}private static class TopKTask extends RecursiveTask<int[]> {private final int[] nums;private final int start, end;private final int k;TopKTask(int[] nums, int start, int end, int k) {this.nums = nums;this.start = start;this.end = end;this.k = k;}@Overrideprotected int[] compute() {if (end - start < THRESHOLD) {return sequentialTopK(nums, start, end, k);}int mid = start + (end - start) / 2;TopKTask left = new TopKTask(nums, start, mid, k);TopKTask right = new TopKTask(nums, mid + 1, end, k);left.fork();int[] rightResult = right.compute();int[] leftResult = left.join();return merge(leftResult, rightResult, k);}private int[] sequentialTopK(int[] nums, int start, int end, int k) {PriorityQueue<Integer> minHeap = new PriorityQueue<>(k);for (int i = start; i <= end; i++) {if (minHeap.size() < k) {minHeap.offer(nums[i]);} else if (nums[i] > minHeap.peek()) {minHeap.poll();minHeap.offer(nums[i]);}}int[] result = new int[k];for (int i = k - 1; i >= 0; i--) {result[i] = minHeap.poll();}return result;}private int[] merge(int[] a, int[] b, int k) {PriorityQueue<Integer> minHeap = new PriorityQueue<>(k);for (int num : a) {if (minHeap.size() < k) {minHeap.offer(num);} else if (num > minHeap.peek()) {minHeap.poll();minHeap.offer(num);}}for (int num : b) {if (minHeap.size() < k) {minHeap.offer(num);} else if (num > minHeap.peek()) {minHeap.poll();minHeap.offer(num);}}int[] result = new int[k];for (int i = k - 1; i >= 0; i--) {result[i] = minHeap.poll();}return result;}}
}

实际应用建议

  1. 内存足够:优先使用最小堆方案,实现简单且效率高

  2. 内存有限:考虑快速选择算法

  3. 超大数据集:使用并行处理方案

  4. 数据存储在外部:考虑分批读取+堆处理的方式

对于1亿个数据,最小堆方案通常是最佳选择,因为它只需要O(n)的时间和O(10)的额外空间。

相关文章:

  • 【数据结构】Map与Set结构详解
  • 开源交易所源码,交易所开发
  • 时序数据库IoTDB构建的能源电力解决方案
  • 无人设备遥控之调度自动化技术篇
  • 从岗位依附到能力生态:AI革命下“什么叫就业”的重构与价值
  • Python3(8) 字符串
  • 使用HYPRE库并行装配IJ稀疏矩阵指南: 矩阵预分配和重复利用
  • 数据集-目标检测系列- F35 战斗机 检测数据集 F35 plane >> DataBall
  • 数据分析之技术干货业务价值​​ powerquery 分组排序后取TOP
  • Code Splitting 分包策略
  • 【网络原理】从零开始深入理解TCP的各项特性和机制.(一)
  • 立錡科技优化 HDD、LPDDR、SoC 供电的高性能降压转换器
  • Python实现技能记录系统
  • 【华为OD机试真题】428、连续字母长度 | 机试真题+思路参考+代码解析(E卷)(C++)
  • Browser-Use WebUI:让AI自动使用浏览器帮你查询信息执行任务
  • StableDiffusionPipeline原理解读——引导尺度是如何调整噪声残差的
  • 【C语言经典算法实战】:从“移动距离”问题看矩阵坐标计算
  • 审计效率升级!快速匹配Excel报表项目对应的Word附注序号
  • Ubuntu / WSL 安装pipx
  • E3650工具链生态再增强,IAR全面支持芯驰科技新一代旗舰智控MCU
  • 冯象|那“交出”后的崩溃,如撒旦坠落诸天
  • 李公明︱一周书记:大学的价值、韧性以及……不相称的对抗
  • 天问三号开放20千克质量资源,邀国际合作开展火星探测研究
  • 宁德时代与广汽等五车企发布10款巧克力换电新车型:年内将完成30城1000站计划
  • “下一个高增长市场,还是中国”,龚正市长会见参加上海车展的国际企业高管
  • 何以中国|福建武夷山:千年茶道的文旅“破圈”与新生