写这个:
N = args[1].split("\\s+").length;
使用命令行参数如:echo "A B C D E F G H I" | java Subset 3
,如果我使用"A B C D E F G H I"
将.split()
字符串解析为字符串数组,它会消耗类似的内存吗?
我的说法是(作为挑战)学生(我)可以尝试从N字符串(N = 9,A到I)随机均匀地显示K个字符串(上面的cmd行中的K = 3) )输入,同时消耗与K成比例的内存,而不是N. 这基本上就是我想要做的事情。
编辑:mvp的回答很有帮助。现在更好地理解这个问题。
但是我觉得我应该补充说我只允许使用它:
private static Scanner scanner = new Scanner(new BufferedInputStream(System.in), charsetName);
我不能单独使用Scanner
课程,或BufferedReader
就此而言。鉴于这种限制,我有点不确定如何继续。
答案 0 :(得分:2)
这可以解决未知长度的输入数据流(也就是说,我们仅停止EOF,并且不关心N是什么),并且将使用与K成比例的存储器。
首先,让我们解决K = 1。如果我们开始阅读输入流,我们应该假设第一个项目(在你的例子中是A)应该是我们的答案 - 因为如果没有输入,那一定是它。当我们阅读第二项时,我们应该考虑将其作为我们的答案,而不是A,概率为1/2
。当我们阅读第3项C时,我们应该以概率1/3
来看待它,依此类推。该算法将从输入流中随机选择1个项目,而不事先知道项目数量(每个项目具有相同的概率)。
对于K = 2,K = 3(或更多),我们采用类似的方法。例如,对于K = 3,请阅读3个项A
,B
,C
并将其用作答案。当我们阅读第4项时,我们应该以{{1}}(K / N)的概率选择它,并用它来替换其中一个活动项,其概率为3/4
。然后继续这样做直到输入流的EOF,最后打印3个活动项目。
答案 1 :(得分:1)
是的,它将使用相同的内容,因为String[]
数组的创建始终是split
数组,即使您没有明确地将其存储在任何位置。
我建议您按以下方式从输入中提取单词:
List wordList
以存储3个字。wordList
中,则将其丢弃并从步骤2开始重复。在此过程中,您只在内存中存储了3个字(K),而不是9(N)。
扫描也可以通过以下方式进行:
import java.util.Scanner;
public class MyProgram {
public static void main(String... args) {
final int K= 3 ;
String[] words= new String[K] ;
int wordCount= 0 ;
int nextWord= 0 ;
Scanner scanner= new Scanner(System.in) ;
while( scanner.hasNext() ) {
String word= scanner.next();
wordCount++;
if( nextWord < K ) {
words[nextWord]= word ;
nextWord++;
} else {
int replacePos= (int)(Math.random()*wordCount) ;
if( replacePos < K ) {
words[replacePos]= word ;
}
}
}
scanner.close();
for(String word: words ) {
System.out.println(word);
}
}
}
答案 2 :(得分:1)
@mvp对于案例K = 1具有正确的解决方案,但是当K> 1时1取项目M的正确概率是K / M,而不是1 / M(在你的情况下,你应该选择概率为3/4的第4项,第5项概率为3/5,依此类推)。
顺便说一下,这被称为reservoir sampling。