前言
我们在进行开发的时候都需要对某个非法的敏感词进行过滤,下面介绍一种用字典树来实现的敏感词过滤小工具(以Java代码实现)
字典树
Trie树,即字典树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高。
Trie的核心思想是空间换时间。利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。
它有3个基本性质:
- 根节点不包含字符,除根节点外每一个节点都只包含一个字符。
- 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
- 每个节点的所有子节点包含的字符都不相同。
实例
- 1、有一个1G大小的一个文件,里面每一行是一个词,词的大小不超过16字节,内存限制大小是1M。返回频数最高的100个词。
- 2、1000万字符串,其中有些是重复的,需要把重复的全部去掉,保留没有重复的字符串。请怎么设计和实现?
- 3、 一个文本文件,大约有一万行,每行一个词,要求统计出其中最频繁出现的前10个词,请给出思想,给出时间复杂度分析。
- 4、寻找热门查询:搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的长度为1-255字节。假设目前有一千万个记录,这些查询串的重复读比较高,虽然总数是1千万,但是如果去除重复和,不超过3百万个。一个查询串的重复度越高,说明查询它的用户越多,也就越热门。请你统计最热门的10个查询串,要求使用的内存不能超过1G。 (1) 请描述你解决这个问题的思路; (2) 请给出主要的处理流程,算法,以及算法的复杂度。
要处理上述问题,我们都可以用字典树来解决
敏感词过滤的实现
Java代码如下
public class SensetiveWordFilter{
private class Trienode{
//定义一个结束标志,为false时表示继续
private boolean end = false;
//key表示下一节点对应的字符,value表示对于的节点
private HashMap<Character,Trienode> subNotes = new HashMap<Character,Trienode>();
//获取下一个节点
Trienode getsubNodes(Character c){
return subNotes.get(c);
}
//添加下一个节点
void addsubNotes(Character c,Trienode node){
subNotes.put)(c,node);
}
//判断是否达到字典树底部
boolean isKeyend(){
return end;
}
//设置字典树底部
void setKeyend(boolean end){
this.end = end;
}
}
//设定根节点
Trienode rootnode = new Trienode();
//将敏感词存入字典树当中
private void addWord(String lineText){
Trienode tempnode = rootnode;
}
for(int i=0;i<lineText.length();i++){
Character c = lineText.charAt(i);
//判断c是否符号
if(isSymbol(c)){
continue;
}
Trienode node = tempnode.getsubNodes(c);
//如果下个节点是空的,添加下个节点
if(node==null){
tempnode.addsubNotes(c,node);
}
tempnode = node;
//设置结束
if(i==lineText.length()-1){
tempnode.setKeyend(true);
}
}
private String Filter(String text){
if (StringUtils.isBlank(text)) {
return text;
}
TrieNode tempnode = rootnode;
StringBuilder result = new StringBuilder();
String replacement = "***";
int begin = 0;//回滚数
int position = 0;//当前位置数
while(position<text.length()){
char c = text.charAt(position);
if(isSymbol(c)){
if(tempnode==rootnode){
result.append(c);
begin++;
}
position++;
continue;
}
tempnode = tempnode.getsubNodes(c);
if(tempnode==null){
//以begin开始的字符串不在字典树内
result.append(beign);
postion = begin+1;
begin = position;
tempnode = rootnode;
}else if(tempnode.isKeyend()){
result.append(replacement);
position = position + 1;
begin = position;
tempNode = rootNode;
}else{
position++;
}
}
result.append();
}
return result.toString();
}