一、题目如下:
给一个整数N和一个特别大内存装不下的纯文本文件,从这个文件随机抽N行文本返回
public List<String> extractLines(String filePath,int n){
//todo 在这里填充代码
}
要求:文件只读一遍,占用的内存最多只有N+1行;每行最多算一个随机数;返回的文本行顺序要跟原文件中的文本行顺序保持一致。
关键是“随机”
以下做法是错的:1.把整个文件一次读到内存再计算随机数;2.使用LineNumberReader;3.预先算n个随机数
二、蓄水池算法
蓄水池算法是针对从一个序列中随机抽取不重复的K个数,保证每个数被抽取到的概率都为K/N这个问题构建的
做法:
首先构造一个可以容纳k个元素的蓄水池,将序列前k个元素直接放入蓄水池中
然后从第k+1个数据开始,以k/i(k<i=n)的概率来决定它是否进入蓄水池。
当遍历完N个数据,蓄水池中所剩的K个元素就是就是挑选出的元素
时间复杂度为O(N)
三、java实现
public static List<String> extractLines(String filePath, int n) throws IOException {
List<String> randomLines = new ArrayList<>();
FileReader fr = new FileReader(filePath);
BufferedReader br = new BufferedReader(fr);
for (int j = 0; j < n; j++) {
String line = br.readLine();
randomLines.add(line);
}
for (int i = 0;; i++) {
String readLine = br.readLine();
if (StringUtils.isBlank(readLine)) {
break;
}
Random random = new Random();
int nextInt = random.nextInt(n + i) ;
if (nextInt < n) {
randomLines.remove(nextInt);
randomLines.add(readLine);
}
}
return randomLines;
}