今天在刷leetcode的时候遇到一道题,大意是给一个集合,里面放了好多单词,再给一个图里面放着一堆字母,相邻的字母可以构成单词,问集合里的单词有多少个能被这么构造出来。
会前缀树之前,反手一个dfs爆搜,超时了,考虑剪枝,其实很多时间都浪费在从一开始就不可能实现的单词上了,所以简简单单在深搜之前判断一下单词中的字母是不是每个都在图里出现过,偷鸡过了。
前缀树其实作用就是剪枝,当我们要对一大堆字符串键值进行处理的时候,可以用空间换取时间,先写个解答树,每个父节点有26个子节点对应26个字母。比如一个单词hello, 第一层只有h有值,第二层是e,第三层是l,第四层也是l,第五层是o。第0层留给null作为树的root节点。
这样写很容易发现每一个非空树节点其实是代表一个单词的前缀,当这个树节点正好代表一个单词的最后一个字母时,我们还可以加个标记表示到这儿为止可以构成一个单词。比如有两个单词care和carefull,前四个字母一样,但是在care的e那个节点上我们要标一下表示接着往下走可以有新单词,这儿也有一个,走过路过不要错过。
就这道题而言,在对图中每一个点依次深搜的时候,我们可以看看当前深搜路径是不是任意单词的前缀,如果不是说明走歪了break吧,是的话就一直走啊走,路上遇到标记就把那个单词加到一个set里表示这个单词我们找到了,可以构造出来,一直走到无路可走,收下最后一个单词,以这个点为起点的路算是用干净了。
对比之前朴素的做法,用前缀树的好处是中途无时无刻不在剪枝,不仅出现陌生字母时会剪枝,出现怪异前缀压根不可能构成单词的时候也会剪枝,