问题
I'm having trouble understanding the concept of a trie. From the "trie" wikipedia entry I have this picture:
If I see this correctly, all leaf nodes in a trie will have the entire word spelled out and all parent nodes hold the characters leading up the the final leaf node. So, if I have a class called DigitalTreeNode defined by
public class DigitalTreeNode {
public boolean isAWord;
public String wordToHere; (compiles all the characters in a word together)
public Map<String, DTN> children;
}
If I wanted to implement a method that returns the longest word in the trie would it simply involve finding the longest word at each leaf node? How would I implement a method such as:
public static String longestWord (DigitalTreeNode d);
I'm guessing it involves setting up a longest String variable, recursively going through each node and checking if it is a word, if it is a word and it's length is greater than the longest variable then longest = newWordLength . But, I'm not sure how the Map children fits in. How would I find the longest word in any trie using the method above?
回答1:
The leaf nodes do not contain the entire string usually (though they can), many time in a trie, a leaf node just contains a '$' sign to indicate this is the end of the string.
To find the longest word in a trie you can use a BFS on the tree, to first find the "last" leaf. The "last leaf" is the last element that was popped out of the BFS queue (after it was popped the algorithm of BFS stopped with an empty queue).
To get the actual word from this leaf you will need to go up from the leaf back to the root. This thread discussed how it can be done.
This solution is O(|S| * n)
, where |S|
is the average length of a string, and n
is the number of string in the DS.
If you can manipulate the trie DS, I assume it can be done better (but it seems not to be the issue in this question)
Pseudo code:
findLongest(trie):
//first do a BFS and find the "last node"
queue <- []
queue.add(trie.root)
last <- nil
map <- empty map
while (not queue.empty()):
curr <- queue.pop()
for each son of curr:
queue.add(son)
map.put(son,curr) //marking curr as the parent of son
last <- curr
//in here, last indicate the leaf of the longest word
//Now, go up the trie and find the actual path/string
curr <- last
str = ""
while (curr != nil):
str = curr + str //we go from end to start
curr = map.get(curr)
return str
回答2:
Another way of doing it is adding a boolean to signify if it's end of word AND the actual word like below:
public class TrieNode {
private HashMap<Character, TrieNode> children = new HashMap<>();
private boolean endOfWord;
private String actualWord;
//setter getter
}
On insert, if it is end of word set boolean to true and the actual word
public void insert(String insert) {
HashMap<Character, TrieNode> parent = root.getChildren();
TrieNode child = null;
for (Character c : insert.toCharArray()) {
child = parent.containsKey(c) ? parent.get(c) : new TrieNode();
parent.put(c, child);
parent = child.getChildren();
}
if (child != null) {
child.setEndOfWord(true);
child.setActualWord(insert);
}
}
Finally fetching it, you just do a BFS search, and once you have that node you have the actual word you are looking for.
public TrieNode findLongest() {
LinkedList<TrieNode> queue = new LinkedList();
queue.push(root);
TrieNode current = null;
while (!queue.isEmpty()) {
current = queue.pop();
if (current.getChildren() != null) {
for (TrieNode children : current.getChildren().values()) {
queue.push(children);
}
}
}
System.out.println(current.getActualWord()); // check here
return current;
}
来源:https://stackoverflow.com/questions/13191942/how-to-find-the-longest-word-in-a-trie