TOP K 问题
比如“从10亿个数字中找出最大的前100个数”,会怎么操作?
我们可以考虑使用小根堆(如果是求最小的前100个数,那么就可以使用大根堆),先顺序取出前100个,建立小根堆后,从第101个开始遍历,如果当前的数字小于小根堆的堆顶元素的话,那就直接丢弃,不考虑,如果是大于堆顶元素的话,那么先把堆顶元素删除后,添加当前的元素......直到全部遍历完成。
关于时间复杂度:建堆的时间复杂度为O(mlogm)(m为数组的大小即为100),然后遍历后续的数字,并于堆顶(最小)数字进行比较。如果比最小的数小,则继续读取后续数字;如果比堆顶数字大,则替换堆顶元素并重新调整堆为最小堆。整个过程直至1亿个数全部遍历完为止。然后按照中序遍历的方式输出当前堆中的所有10000个数字。该算法的时间复杂度为O(nmlogm),空间复杂度是100(常数)。
这种方法对于内存的要求不高,并且也只需遍历一次即可。唯一不足的就是,单机运行可能效果不好。
如果是多机环境的话,可以考虑使用MapReduce,增加可拓展性:
public class WordCountMapper extends Mapper<LongWritable, Text, Text,IntWritable> { private static IntWritable data = new IntWritable(); //静态变量了解一下 @Override protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, IntWritable>.Context context) throws IOException, InterruptedException { String line = value.toString(); data.set(Integer.parseInt(line)); context.write(data, new IntWritable(1));//就用1作为value即可 } } } public class MyReducer extends Reducer<IntWritable, IntWritable, IntWritable, IntWritable>{ public void reduce(IntWritable key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException{ for(IntWritable val : values){ context.write(data, key); break;//重复的数字我只采用一次 } } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步