这是腾讯的一道面试题,因为平时这方面接触比较少,所以想法比较浅。
虽然最终没有通过面试,但仍然记录如下,希望以后回头看的时候能够想出更好的答案。
或许可以问下博客园的开发,下文中的脏子竟然被禁止使用了,只能用xx代替之。
题目:网络发表评论模块设计时会有一个难题,用户的输入的聊天字符串要进行过滤,如果其中含有脏话,比如中文的“他妈的”,英文的“Fuck”,。就必须将这些脏话进行过滤,替换。聊天模块有一个脏话库,脏话库中含有多个要求过滤的词汇。请你设计一个算法对发表评论输入字符串的脏话过滤,同时请描述你的算法的大致的时间复杂度。
举例:中文“他妈的,我要找到那个联盟。”要过滤掉“------,我要……”,英文“Fuck you,I want to find”,要过滤成”---- you, I want to find”。
一、分析
1) 看到这个题目首先想到的是选择一个高效的字符串匹配算法,于是先到KMP算法。但是细想,KMP虽然充分利用了匹配失败部分的比较信息,但是这仅限于一个字符串的匹配。当有很多字符串需要匹配的时候,KMP无法利用已匹配过的字符串的匹配信息。比如字符串”abcefgh”匹配”abcd”失败之后,再接着匹配”abce”的话,仍然是重新从第一个字符开始比较,事实上,”abc”已经比较过了。因此,如果算法能够共享所有关键字间的匹配信息的话,应该可以大大提高效率,尤其是关键字数目较多的情况下。
2) 另一方面,我们来看脏字串的特点。如”x你大爷的”和”x你妈的”, “fuck you”和”fuck your ..”,他们有一个特点,就是脏话之间往往带有共同的前缀。脏字的这个特点,更加坚定了1)的想法。
二、设计
那么如何设计一种结构使得所有脏字在匹配的时候能够共享匹配信息的,trie树就是一个很好的结构。这里每个son分支对应一个字节的字符,而下表采用该字符的ascii。这样可以实现O(1)的字符查找,而脏字较多的情况下也不好浪费太多空间。
脏字替换伪代码:
1 for byte in bytes 2 if byte not found 3 rollback, 从下一个byte开始找 4 else if 找到一个串 5 替换该串,从串的下一个byte开始找 6 else if byte found 7 记录该byte, 沿着trie继续查
三、总结
1) 时间复杂度为O(NK), N为输入字符串长度,K为最长脏字长度;
2) 暂时采用的是贪婪查询,查询到最短的脏字就直接替换了;