2024年最全如何实现一个高效的关键词过滤功能?——DFA算法(1),分布式架构演进+相关笔记参考

1200页Java架构面试专题及答案

小编整理不易,对这份1200页Java架构面试专题及答案感兴趣劳烦帮忙转发/点赞

百度、字节、美团等大厂常见面试题

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

Set haveWordSet = new HashSet();

for (String word : wordSet) {

if (content.contains(word)) {

haveWordSet.add(word);

}

}

System.out.println(haveWordSet);

}

}

// [产品经理]

思路很简单,也很容易理解,但是当关键词有几千、几万个时,性能会急剧下降。分析一下时间复杂度,遍历关键词是O(n),从文字段落检索的时间复杂度也是O(n),合起来就是O(n^2)。

有没有其他更优的解决方案呢?有!就是DFA算法!

二、何为DFA算法


DFA即Deterministic Finite Automaton,翻译过来就是确定性有限自动机。简单原理就是:在一个有限的集合,其中的元素都有两种状态,结束和继续(可以用0代表继续,1代表结束),可以从一个元素检索到下一个元素,直到元素的状态为结束为止。

dfa

三、DFA算法优化关键词过滤


套用DFA算法的原理,例如有一些关键词:产品经理、产品总监、程序员,构建DFA算法容器如下:

java-dfa

看着像一棵棵树,现在判断一个词是否在词库中,比如测试员,检索是否有”测“字开头的“树”,很快就能判断没有测试员这个词,比如检索“产品经理”,则可以找到”产“字开头的“树”,直接排除了“程序员”那棵“树”,这就大大缩小了范围。

算一下时间复杂度,从词库中匹配关键词,时间复杂度是O(1),遍历文字段落依然和文字的个数有关,时间复杂度最差(如果文本没有一个关键词)为O(n),合起来就是小于等于O(n)。使用DFA实现关键词过滤的优化点在于:检索的时间复杂度不会因为关键词数量的增加而受影响,只与被检索的文字长度有关。

四、java代码实现


分析数据结构,每一个字符都要存一个状态,可以用map实现,如果状态未结束还要存下一个字符的指针,也可以用map实现,这样就是map套map。如下:一个大map里有两个key,程和产,value值又是map套map。

{程={isEnd=0,

序={isEnd=0,

员={isEnd=1}

}

},

产={isEnd=0,

品={isEnd=0,

总={isEnd=0,

监={isEnd=1}

},

经={isEnd=0,

理={isEnd=1}

}

}

}

}

完整代码示例:

public class Test131 {

public static void main(String[] args) {

String content= “产品经理工作内容包含需求收集,需求分析,需求落地,项目跟踪,项目上线,数据跟踪以及对业务人员进行培训,协助运营、销售、客服等开展工作。”;

Set wordSet = new HashSet();

wordSet.add(“产品经理”);

wordSet.add(“产品总监”);

wordSet.add(“程序员”);

init(wordSet);

System.out.println(“wordMap=” + m_kwWordMap);

Set haveWords = getWord(content, MIN_MATCH_TYPE);

System.out.println(“haveWords=” + haveWords);

}

/**

  • 初始化DFA关键词容器

  • @param words

*/

@SuppressWarnings({ “rawtypes”, “unchecked” })

public static void init(Set words) {

// 预先 设置初始容量,以免扩容影响性能。

Map wordMap = new HashMap(words.size());

for (String word : words) {

Map nowMap = wordMap;

for (int i = 0; i < word.length(); i++) {

// 转换成char型

char keyChar = word.charAt(i);

// 判断是否已经有一个map树,只有在一个词的首字符有用

Object tempMap = nowMap.get(keyChar);

if (tempMap != null) {

// 存在,则共享一个map树根

nowMap = (Map) tempMap;

}

// 不存在则构建一个map树,

else {

// 设置状态位

Map<String, String> newMap = new HashMap<String, String>();

// 判断是设置 0还是1

newMap.put(“isEnd”, i == word.length() - 1 ? “1” : “0”);

// 给keyChar该字符设置状态位

nowMap.put(keyChar, newMap);

// 将状态位map赋值给nowMap,表示下一个字符的指针和状态位在同一个map里。

nowMap = newMap;

}

}

}

// 上面始终修改的是nowMap,最后形成的是wordMap,原因是,预先wordMap赋值给了nowMap,

// 使得wordMap和nowMap中的map地址值共享,更新了nowMap中的map就是更新了wordMap。

m_kwWordMap = wordMap;

}

/**

  • 检索关键词

  • @param txt 被检索的文本

  • @param beginIndex 被检索文本的开始位置

  • @param matchType 匹配类型

  • @return 返回检索到的关键词长度,用于从文本中截取

*/

public static int checkWord(String txt, int beginIndex, int matchType) {

// 匹配标识数默认为0

Map nowMap = m_kwWordMap;

int matchFlag = 0;

int matchMaxFlag = 0;

for (int i = beginIndex; i < txt.length(); i++) {

char word = txt.charAt(i);

// 获取指定key

nowMap = (Map) nowMap.get(word);

// 存在,则判断是否为最后一个

最后

金三银四到了,送上一个小福利!

image.png

image.png

专题+大厂.jpg

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

g-UdgZOwr5-1715109369059)]

[外链图片转存中…(img-JPmyotfa-1715109369059)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值