【算法面试】TopN问题

竹石

 

作者:郑燮

 

咬定青山不放松,立根原在破岩中。

千磨万击还坚劲,任尔东西南北风。

 前言

 又到了一年一度的南北人口大迁移的时候,没有买票的赶紧买票,今年很早就已经回家准备过年了,因为小编已经离职啦,最近正在积极复习找工作,闲话不多扯,开始今天的正题。

面试题目:如何在10亿个整数中找出前1000个最大的数。

 这就是有名的TopN问题,这样的问题有很多种解法,下面我对我了解的解法做一个总结并写出最优算法。

如果初次听到这样的题目,我相信大家和我的第一反应都是一样的,先排序后输出前1000个,那么多排序,归并排序快速排序堆排序。。。

那么问题来了,排序的复杂度太大,数据量又是上亿级别的,明显排序方案不合理。那么我们能否不要全排,只排序部分元素,不就可以了吗?

 

方法一:冒泡排序

由此想到冒泡排序的原理:通过两层for循环,外层第一次循环找到数组中最大的元素放置在倒数第一个位置,第二次循环找到第二大的元素放置在倒数第二个位置。。。循环N次就可以找到TopN。

缺点:冒泡排序内层循环需要大量交换元素。复杂度介于O(n)和O(n^2)之间。

 

方法二:分而治之

由快速排序原理可知:选一个基准元素,每次排序可以将这个基准元素搁置在正确的位置,左边都是比基准小的元素,右边都是比基准大的元素从而将数组分成左右两部分,分而治之。TopN问题也同样如此,选择一个基准元素并通过快速排序将基准元素搁置在正确的位置,如果左边的元素个数小于1000,那么继续从基准右边排序,如果左边元素个数大于1000,那么从基准左边排序,直到基准的位置正好在1000,结束。

缺点:第一次排序复杂度是O(n),第二次排序复杂度是O(n/2),第三次排序复杂度是O(n/4)...

 

 方法三:文件存储,分而治之

将比基准小的元素存储在txt1中,比基准大的文件存储在txt2中,然后通过类似方法二的形式,最后求出TopN。

缺点:磁盘读取,写入次数过多。

 

方法四:分布式、MapReduce

单机内存和性能确实受限,那么我们

虽然给定引用未直接提及Java面试必刷的前101个算法,但可以从引用中获取一些关于Java面试高频算法的信息。在Java开发岗位面试中,算法题目占比达70%以上,掌握核心算法思想有助于通过技术面试和提升编程能力 [^1]。对于应届毕业生,算法是大厂校招重点考察科目,而社招一般较常考察冒泡和快排,最好能手写代码 [^2]。 通常Java面试高频算法题型包括字符串处理等 [^1]。常见的排序算法如冒泡排序、选择排序、快速排序、插入排序、堆排序、希尔排序、归并排序和基数排序也是重要考察内容,这些算法的思想、复杂度分析等都可能会被问到 [^3]。 不过,确切的前101个必刷算法没有在引用中给出,一般可以通过专业的算法学习网站如LeetCode、牛客网等,结合相关的Java面试算法书籍来系统梳理出这101个算法。以下为部分常见算法及示例代码: ### 冒泡排序 ```java public class BubbleSort { public static void bubbleSort(int[] arr) { int n = arr.length; for (int i = 0; i < n - 1; i++) { for (int j = 0; j < n - i - 1; j++) { if (arr[j] > arr[j + 1]) { // 交换 arr[j+1] 和 arr[j] int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } } public static void main(String[] args) { int[] arr = {64, 34, 25, 12, 22, 11, 90}; bubbleSort(arr); for (int num : arr) { System.out.print(num + " "); } } } ``` ### 快速排序 ```java public class QuickSort { public static void quickSort(int[] arr, int low, int high) { if (low < high) { int pi = partition(arr, low, high); quickSort(arr, low, pi - 1); quickSort(arr, pi + 1, high); } } private static int partition(int[] arr, int low, int high) { int pivot = arr[high]; int i = (low - 1); for (int j = low; j < high; j++) { if (arr[j] < pivot) { i++; int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } } int temp = arr[i + 1]; arr[i + 1] = arr[high]; arr[high] = temp; return i + 1; } public static void main(String[] args) { int[] arr = {10, 7, 8, 9, 1, 5}; int n = arr.length; quickSort(arr, 0, n - 1); for (int num : arr) { System.out.print(num + " "); } } } ``` ### 字符串反转 ```java public class ReverseString { public static String reverseString(String str) { return new StringBuilder(str).reverse().toString(); } public static void main(String[] args) { String str = "Hello"; System.out.println(reverseString(str)); } } ```
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值