Trie字典树主要用于存储字符串,Trie的每个Node保存一个字符。用链表来描述的话,就是一个字符串就是一个链表。每个Node都保存了它的所有子节点。
如下图所示,根节点不包含任何信息。每个节点表示一个字符串中的字符,从根节点到红色节点的一条路径表示一个字符串。红色节点不一定是叶子节点。
使用Trie这种数据结构存储字符串,查询每个字符串的时间复杂度,只和该字符串长度相同。
创建一个名为TrieNode的类,该类就是我们需要去完善形成的一个Trie的数据结构类。其中有一个Node内部类,Node用来代表Trie中的每一个节点,其中isWord表示首节点到该节点的路径是一个单词,next指向了下一个节点。
public class TrieNode {
//是不是敏感词的结尾
private boolean end = false;
//Character代表当前节点的字符,TrieNode代表了下一个节点
private Map subNodes = new HashMap<>();
public void addSubNode(Character key, TrieNode node) {
subNodes.put(key, node);
}
//查看下一个节点有没有对应的字符
TrieNode getNextSubNode(Character key) {
return subNodes.get(key);
}
boolean isEndWord() {
return end;
}
void setEndWord(boolean end) {
this.end = end;
}
}
将传入的word进行遍历添加到Trie的分支上,对于已经存在的字符就不用再添加
private TrieNode root = new TrieNode();
public void addWord(String word){
TrieNode tempNode = root;
for(int i = 0 ; i < word.length();i++){
Character c = word.charAt(i);
//判断该字符是否已存在
TrieNode node = tempNode.getNextSubNode(c);
//若不存在则添加
if(node == null){
node = new TrieNode();
tempNode.addSubNode(c,node);
}
tempNode = node;
if(i == word.length()-1){
tempNode.setEndWord(true);
}
}
}
需要将待查询的word的每个字符遍历看是否存在,将传入的字符串中不是敏感词的就加入到StringBuilder中,如果是敏感词则用***代替。
public String filter(String words){
String replacement = "***";
TrieNode tempNode = root;
int begin = 0;
int position = 0;
StringBuilder result = new StringBuilder();
while(position < words.length()){
char c = words.charAt(position);
tempNode = tempNode.getNextSubNode(c);
//如果这个字符不在敏感词中则添加到结果中
if(tempNode == null){
result.append(words.charAt(begin));
position = begin+1;
begin = position;
tempNode = root;
}else if(tempNode.isEndWord()){
//发现敏感词进行打码
result.append(replacement);
position += 1;
begin = position;
tempNode = root;
}else{
++position;
}
}
//把最后一串加上
result.append(words.substring(begin));
return result.toString();
}
public class main {
public static void main(String[] args) {
Trie trie = new Trie();
trie.addWord("色情");
System.out.println(trie.filter("hello,色情"));
}
}
public class main {
public static void main(String[] args) {
Trie trie = new Trie();
trie.addWord("色情");
System.out.println(trie.filter("hello,色 情"));
}
}
0x2E80,0x9FFF是东亚文字的范围
public boolean isSymbol(char c){
int ic = (int)c;
//如果不是东亚文字则返回false
if(ic<0x2E80 || ic>0x9FFF)
return false;
return true;
}
在过滤方法中进行调用
public class main {
public static void main(String[] args) {
Trie trie = new Trie();
trie.addWord("色情");
System.out.println(trie.filter("hello,色&&^@情,色, 情"));
}
}