Java 如何从Trie中检索给定长度的随机字
我有一个简单的Trie,用来存储长度为2-15的大约80k个单词。它非常适合检查字符串是否是单词;然而,现在我需要一种获得给定长度的随机单词的方法。换句话说,我需要“getRandomWord(5)”返回一个5个字母的单词,所有5个字母的单词都有相同的机会被返回 我能想到的唯一方法是选择一个随机数,首先遍历树的宽度,直到我通过了所需长度的许多单词。有更好的方法吗 可能没有必要,但这是我的trie代码Java 如何从Trie中检索给定长度的随机字,java,algorithm,data-structures,tree,trie,Java,Algorithm,Data Structures,Tree,Trie,我有一个简单的Trie,用来存储长度为2-15的大约80k个单词。它非常适合检查字符串是否是单词;然而,现在我需要一种获得给定长度的随机单词的方法。换句话说,我需要“getRandomWord(5)”返回一个5个字母的单词,所有5个字母的单词都有相同的机会被返回 我能想到的唯一方法是选择一个随机数,首先遍历树的宽度,直到我通过了所需长度的许多单词。有更好的方法吗 可能没有必要,但这是我的trie代码 class TrieNode { private TrieNode[] c; p
class TrieNode {
private TrieNode[] c;
private Boolean end = false;
public TrieNode() {
c = new TrieNode[26];
}
protected void insert(String word) {
int n = word.charAt(0) - 'A';
if (c[n] == null)
c[n] = new TrieNode();
if (word.length() > 1) {
c[n].insert(word.substring(1));
} else {
c[n].end = true;
}
}
public Boolean isThisAWord(String word) {
if (word.length() == 0)
return false;
int n = word.charAt(0) - 'A';
if (c[n] != null && word.length() > 1)
return c[n].isThisAWord(word.substring(1));
else if (c[n] != null && c[n].end && word.length() == 1)
return true;
else
return false;
}
}
编辑:有标记的答案很有效;我将在这里为子孙后代添加我的实现,以防它帮助任何有类似问题的人
首先,我创建了一个helper类来保存我在搜索中使用的三节点的元数据:
class TrieBranch {
TrieNode node;
int letter;
int depth;
public TrieBranch(TrieNode n, int l, int d) {
letter = l; node = n; depth = d;
}
}
这个类保存Trie并实现对随机词的搜索。我是一个初学者,所以可能有更好的方法来做到这一点,但我测试了一点,它似乎工作。没有错误处理,因此请注意清空
class Dict {
final static int maxWordLength = 13;
final static int lettersInAlphabet = 26;
TrieNode trie;
int lengthFrequencyByLetter[][];
int totalLengthFrequency[];
public Dict() {
trie = new TrieNode();
lengthFrequencyByLetter = new int[lettersInAlphabet][maxWordLength + 1];
totalLengthFrequency = new int[maxWordLength + 1];
}
public String getRandomWord(int length) {
// Returns a random word of the specified length from the trie
// First, pick a random number from 0 to [number of words with this length]
Random r = new Random();
int wordIndex = r.nextInt(totalLengthFrequency[length]);
// figure out what the first letter of this word would be
int firstLetter = -1, totalSoFar = 0;
while (totalSoFar <= wordIndex) {
firstLetter++;
totalSoFar += lengthFrequencyByLetter[firstLetter][length];
}
wordIndex -= (totalSoFar - lengthFrequencyByLetter[firstLetter][length]);
// traverse the (firstLetter)'th node of trie depth-first to find the word (wordIndex)'th word
int[] result = new int[length + 1];
Stack<TrieBranch> stack = new Stack<TrieBranch>();
stack.push(new TrieBranch(trie.getBranch(firstLetter), firstLetter, 1));
while (!stack.isEmpty()) {
TrieBranch n = stack.pop();
result[n.depth] = n.letter;
// examine the current node
if (n.depth == length && n.node.isEnd()) {
wordIndex--;
if (wordIndex < 0) {
// search is over
String sResult = "";
for (int i = 1; i <= length; i++) {
sResult += (char)(result[i] + 'a');
}
return sResult;
}
}
// handle child nodes unless they're deeper than target length
if (n.depth < length) {
for (int i = 25; i >= 0; i--) {
if (n.node.getBranch(i) != null)
stack.push(new TrieBranch(n.node.getBranch(i), i, n.depth + 1));
}
}
}
return "failure of some sort";
}
}
类Dict{
最终静态int maxWordLength=13;
最终静态int字母sinalphabet=26;
三电极三电极;
int lengthFrequencyByLetter[];
整数总长度频率[];
公开宣言{
trie=新的三节点();
lengthFrequencyByLetter=新整数[字母表][maxWordLength+1];
totalLengthFrequency=新整数[maxWordLength+1];
}
公共字符串getRandomWord(整数长度){
//从trie返回指定长度的随机字
//首先,从0到[number of words with this length]之间选择一个随机数
随机r=新随机();
int-wordIndex=r.nextInt(总长度频率[长度]);
//找出这个单词的第一个字母是什么
int firstLetter=-1,totalSoFar=0;
(totalSoFar为确保获得每个5个字母的单词的机会均等,您需要知道树中有多少个5个字母的单词。因此,在构建树时,您将要添加的单词长度添加到两个计数器:一个总体频率计数器和一个逐字母频率计数器:
int lengthFrequencyByLetter[letterIndex][maxWordLength-1]
int totalLengthFrequency[maxWordLength-1]
如果你有4000个5个字母的单词,其中213个以“d”开头,那么
及
完成后,将所有内容添加到树中。(字母“a”为0,“b”为1,…“z”为25。)
从这里,您可以搜索给定长度的n
第个单词,其中n
是从均匀随机分布中选取的随机整数,范围为(0,totalLengthFrequency[length-1]
)
假设你的结构中有4000个5个字母的单词。你选择了随机数1234。现在你可以检查了
lengthFrequencyByLetter[0][4]
lengthFrequencyByLetter[1][4]
lengthFrequencyByLetter[2][4]
lengthFrequencyByLetter[3][4]
反过来,直到你的总数超过1234。然后你很快就知道1234个5个字母单词的起始字母是什么,然后在那里搜索。你不必每次都从一开始就搜索树中的每个单词。谢谢,我现在觉得自己很笨!我还没有尝试过,但这很有意义,而且我很确定它会满足我的目的。
totalLengthFrequency[4] = 4000
lengthFrequencyByLetter[0][4]
lengthFrequencyByLetter[1][4]
lengthFrequencyByLetter[2][4]
lengthFrequencyByLetter[3][4]