java 单词树,Trie tree(字典树)的Java兑现及其应用-统计以某字符串为前缀的单词的数量...

Trie tree(字典树)的Java实现及其应用-统计以某字符串为前缀的单词的数量

import java.util.LinkedList;

public class CaseInsensitiveTrie {

/**

字典树的Java实现。实现了插入、查询以及深度优先遍历。

Trie tree's java implementation.(Insert,Search,DFS)

Problem Description

Ignatius最近遇到一个难题,老师交给他很多单词(只有小写字母组成,不会有重复的单词出现),现在老师要他统计出以某个字符串为前缀的单词数量(单词本身也是自己的前缀).

Input

输入数据的第一部分是一张单词表,每行一个单词,单词的长度不超过10,它们代表的是老师交给Ignatius统计的单词,一个空行代表单词表的结束.第二部分是一连串的提问,每行一个提问,每个提问都是一个字符串.

注意:本题只有一组测试数据,处理到文件结束.

Output

对于每个提问,给出以该字符串为前缀的单词的数量.

Sample Input

banana

band

bee

absolute

acm

ba

b

band

abc

Sample Output

2

3

1

0

*/

private int SIZE = 26;// 26 letters.CaseInsensitive.

private TrieNode root;

CaseInsensitiveTrie() {

root = new TrieNode();

}

private class TrieNode {

private int num;// how many words go through this node.

private TrieNode[] son;// TrieNode[26] in this case

private boolean isEnd;// end of a string.

private char val;// No this field mostly.

// But I think it's easy to traverse when having a specific value in

// each node.

private boolean visited;// add this field for DFS

TrieNode() {

num = 1;//num=0 is wrong

son = new TrieNode[SIZE];

isEnd = false;

visited = false;

}

}

public void insert(String str) {

if (str == null || str.length() == 0) {

return;

}

TrieNode node = root;

char[] letters=str.toCharArray();

for (int i = 0, len = str.length(); i < len; i++) {

int pos = letters[i] - 'a';

if (node.son[pos] == null) {

node.son[pos] = new TrieNode();

node.son[pos].val = letters[i];

} else {

node.son[pos].num++;//for 'countPrefix(String prefix)'

}

node = node.son[pos];

}

node.isEnd = true;

}

/**

* count how many words start with the specific prefix.

* since we count it in insertion,what we need to do is to return the 'num' of the last letter of prefix.

*/

public int countPrefix(String prefix){

if(prefix==null||prefix.length()==0){

return -1;

}

TrieNode node=root;

char[] letters=prefix.toCharArray();

for(int i=0,len=prefix.length();i

int pos=letters[i]-'a';

if(node.son[pos]==null){

return 0;

}else{

node=node.son[pos];

}

}

return node.num;

}

// search a word in the tree.Complete matching.

public boolean has(String str) {

if (str == null || str.length() == 0) {

return false;

}

TrieNode node = root;

char[] letters=str.toCharArray();

for (int i = 0, len = str.length(); i < len; i++) {

int pos = letters[i] - 'a';

if (node.son[pos] != null) {

node = node.son[pos];

} else {

return false;

}

}

return node.isEnd;

}

// DFS.Use stack.Like a 26-nary tree.

public void printAllWords() {

TrieNode rootNode = root;

if (root == null){

return;

}

LinkedList list = new LinkedList();

for (int i = 0; i < SIZE; i++) {

TrieNode node = rootNode.son[i];

if (node != null) {

list.addLast(node);

while (!list.isEmpty()) {

TrieNode curNode = list.getLast();

TrieNode firstChild = firstChildOf(curNode);

while (firstChild != null) {

list.addLast(firstChild);

firstChild = firstChildOf(firstChild);// DFS.

}

TrieNode strEnd = list.getLast();

if (strEnd.isEnd) {

printLinkedList(list);

}

list.removeLast();

}

}

list.clear();

}

}

//print each node in preOrder.

public void preTraverse(TrieNode node){

if(node!=null){

System.out.print(node.val+"-");

for(TrieNode child:node.son){

preTraverse(child);

}

}

}

// get the first unvisited child of a node.

public TrieNode firstChildOf(TrieNode node) {

if (node == null)

return null;

for (int i = 0; i < SIZE; i++) {

TrieNode tmp = node.son[i];

if (tmp != null && !tmp.visited) {

tmp.visited = true;

return tmp;

}

}

return null;

}

public static void printLinkedList(LinkedList list) {

if (list == null || list.size() == 0){

return;

}

StringBuilder sb = new StringBuilder();

for (int i = 0, len = list.size(); i < len; i++) {

sb.append(list.get(i).val);

}

System.out.println(sb.toString());

}

public TrieNode getRoot(){

return this.root;

}

public static void main(String[] args) {

CaseInsensitiveTrie tree = new CaseInsensitiveTrie();

String[] strs={

"banana",

"band",

"bee",

"absolute",

"acm",

};

String[] prefix={

"ba",

"b",

"band",

"abc",

};

for(String str:strs){

tree.insert(str);

}

System.out.println(tree.has("abc"));

tree.preTraverse(tree.getRoot());

System.out.println();

tree.printAllWords();

for(String pre:prefix){

int num=tree.countPrefix(pre);

System.out.println(pre+" "+num);

}

}

}

另一道类似的题目:

Description

Given a list of phone numbers, determine if it is consistent in the sense that no number is the prefix of another. Let's say the phone catalogue listed these numbers:

Emergency 911

Alice 97 625 999

Bob 91 12 54 26

In this case, it's not possible to call Bob, because the central would direct your call to the emergency line as soon as you had dialled the first three digits of Bob's phone number. So this list would not be consistent.

Input

The first line of input gives a single integer, 1 ≤ t ≤ 40, the number of test cases. Each test case starts with n, the number of phone numbers, on a separate line, 1 ≤ n ≤ 10000. Then follows n lines with one unique phone number on each line. A phone number is a sequence of at most ten digits.

Output

For each test case, output "YES" if the list is consistent, or "NO" otherwise.

Sample Input

2

3

911

97625999

91125426

5

113

12340

123440

12345

98346

Sample Output

NO

YES

这道题用TrieTree也好做:在插入某个号码时候,如果遇到一个节点已经isEnd==true而号码还没有插入完成,则返回NO

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Trie字典Java代码实现可以分为以下几部分: 1. 定义Trie节点类,包含children数组和isEndOfWord标识,用于表示是否是单词的结尾。 2. 定义Trie类,包含插入、查找和删除操作。 3. 在Trie类中实现插入操作,遍历字符串每一个字符,在Trie中寻找对应节点,如果不存在则新建节点。 4. 在Trie类中实现查找操作,遍历字符串每一个字符,在Trie中寻找对应节点,如果找到最后一个字符对应的节点的isEndOfWord标识为true,则说明字符串单词。 5. 在Trie类中实现删除操作,遍历字符串每一个字符,在Trie中寻找对应节点,如果找到最后一个字符对应的节点的isEndOfWord标识为true,则将其设为false,并删除空节点。 如果需要完整代码和注释请告诉我。 ### 回答2: Trie字典)是一种常用的数据结构,用于高效地存储和查找字符串。下面是Trie字典Java代码实现,用于返回单词。 ```java class TrieNode { private TrieNode[] children; private boolean isEndOfWord; public TrieNode() { children = new TrieNode[26]; // 字母表的大小为26 isEndOfWord = false; } public void insert(String word) { TrieNode curr = this; for (char c : word.toCharArray()) { if (curr.children[c - 'a'] == null) { curr.children[c - 'a'] = new TrieNode(); } curr = curr.children[c - 'a']; } curr.isEndOfWord = true; } public boolean search(String word) { TrieNode node = searchPrefix(word); return node != null && node.isEndOfWord; } public boolean startsWith(String prefix) { TrieNode node = searchPrefix(prefix); return node != null; } private TrieNode searchPrefix(String prefix) { TrieNode curr = this; for (char c : prefix.toCharArray()) { if (curr.children[c - 'a'] == null) { return null; } curr = curr.children[c - 'a']; } return curr; } } public class Trie { private TrieNode root; public Trie() { root = new TrieNode(); } public void insert(String word) { root.insert(word); } public boolean search(String word) { return root.search(word); } public boolean startsWith(String prefix) { return root.startsWith(prefix); } } public class Main { public static void main(String[] args) { Trie trie = new Trie(); trie.insert("apple"); trie.insert("app"); System.out.println(trie.search("apple")); // 输出:true System.out.println(trie.startsWith("app")); // 输出:true System.out.println(trie.search("banana")); // 输出:false } } ``` 以上代码中,`TrieNode`表示Trie的节点,`Trie`表示Trie的结构。其中`TrieNode`类包含了插入单词、查找单词(完全匹配)以及查找前缀的功能。`Trie`类则是对外提供插入、查找单词前缀的方法。 在`main`方法中,我们演示了如何使用`Trie`类来插入和查找单词。首先,我们插入了两个单词"apple"和"app"。然后分别调用`search`方法来查找"apple"和"banana",以及`startsWith`方法来查找以"app"开头的单词。最后,打印出对应的结果,即是否找到了对应的单词前缀。 以上是Trie字典Java代码实现,用于返回单词。 ### 回答3: Trie字典是一种经典的数据结构,用于高效地存储和查找字符串集合。下面是一个基于JavaTrie字典的代码实现,可以实现返回单词的功能: ```java class TrieNode { private final int ALPHABET_SIZE = 26; private TrieNode[] children; private boolean isEndOfWord; public TrieNode() { children = new TrieNode[ALPHABET_SIZE]; isEndOfWord = false; } } class Trie { private TrieNode root; public Trie() { root = new TrieNode(); } public void insert(String word) { TrieNode current = root; for (int i = 0; i < word.length(); i++) { char ch = word.charAt(i); int index = ch - 'a'; if (current.children[index] == null) { current.children[index] = new TrieNode(); } current = current.children[index]; } current.isEndOfWord = true; } public boolean search(String word) { TrieNode current = root; for (int i = 0; i < word.length(); i++) { char ch = word.charAt(i); int index = ch - 'a'; if (current.children[index] == null) { return false; } current = current.children[index]; } return current != null && current.isEndOfWord; } public List<String> getAllWords() { List<String> result = new ArrayList<>(); TrieNode current = root; StringBuilder sb = new StringBuilder(); getAllWordsUtil(current, sb, result); return result; } private void getAllWordsUtil(TrieNode node, StringBuilder sb, List<String> result) { if (node == null) { return; } if (node.isEndOfWord) { result.add(sb.toString()); } for (int i = 0; i < ALPHABET_SIZE; i++) { if (node.children[i] != null) { sb.append((char)('a' + i)); getAllWordsUtil(node.children[i], sb, result); sb.deleteCharAt(sb.length() - 1); } } } } public class Main { public static void main(String[] args) { Trie trie = new Trie(); String[] words = {"hello", "world", "java", "programming"}; for (String word : words) { trie.insert(word); } List<String> allWords = trie.getAllWords(); System.out.println("All words in trie: " + allWords); } } ``` 上述代码中,TrieNode类表示字典的节点,包括一个指向子节点的数组和一个标记,用于表示节点是否是某个单词的结尾。Trie类封装了字典的操作,包括插入单词、查找单词和返回所有单词的功能。在代码的主函数中,我们创建一个Trie对象并插入一些单词,然后调用getAllWords()方法返回字典中的所有单词。最后,打印出返回的单词列表。 希望以上解答对您有所帮助,如有更多疑问,请继续追问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值