题目描述(困难难度)

    79 题 Word Search 的延续。

    意思就是从某个字符出发,然后它可以向左向右向上向下移动,走过的路径构成一个字符串,判断是否能走出给定字符串的 word ,还有一个条件就是走过的字符不能够走第二次。

    比如 eat,从第二行最后一列的 e 出发,向左移动,再向左移动,就走出了 eat。

    题目中给一个 word 列表,要求找出哪些单词可以由 生成。

    解法一

    直接利用 79 题 的代码 ,79 题是判断某个单词能否在 board 中生成。这里的话,很简单,直接遍历 words 数组,然后利用 79 题的代码去依次判断即可。

    使用的时候采用 dfs ,没做过的话大家可以先过去看一下。

    然后它竟然过了,竟然过了。。。我还以为这么暴力一定会暗藏玄机。不过为了尊重它是一道 hard 的题目,我就继续思考能不能优化下。

    顺着上边的思路想,首先 79 题 中判断单个单词是否能生成肯定不能优化了,不然之前肯定会写优化方法。那么继续优化的话,就只能去寻求不同 word 的之间的联系了。

    什么意思呢?

    或者知道了某个单词不能生成,对于后边将要判断的单词能不能提供些帮助呢?

    想了想,只想到了一种情况。比如我们已经知道了 basketboard 能够在二维数组 board 中生成。那么它的所有前缀一定也能生成,比如 basket 一定能够生成。

    说到前缀,自然而然的想到了之前的前缀树,这几天出现的频率也比较高,刚做的 也用到了。我们可以把能生成的 word 加入到前缀树中,然后再判断后边的单词前,先判断它是不是前缀树中某个单词的前缀。

    当然如果单词 是 B 的前缀,那么 A 的长度肯定短一些,所以我们必须先判断了较长的单词 B,才能产生优化的效果。所以我们首先要把 words 按照单词的长度从大到小排序。

    小弟不才,只想到了这一种联系,下边是代码,前缀树直接搬 208 题 的代码即可。

    然而事实是残酷的,对于 leetcodetest cases ,这个想法并没有带来速度上的提升。于是就去逛 discuss 了,也就是下边的解法二。

    解法二

    参考 这里)。

    解法一中的想法是, -> 从图中的每个位置出发,看能否找到这个单词

    我们其实可以倒过来。从图中的每个位置出发 -> 看遍历过程中是否遇到了 words 中的某个单词

    至于实现的话,我们可以在遍历过程中,将当前路径的单词传进函数,然后判断当前路径构成的单词是否是在前缀树中出现即可。

    这个想法可行,但不够好,因为每次都从前缀树中判断当前路径的单词,会带来重复的判断。比如先判断了 an 存在于前缀树中,接下来假如路径变成 ang ,判断它在不在前缀中,又需要判断一遍 an

    因此,我们可以将前缀树融合到我们的算法中,递归中去传递前缀树的节点,判断当前节点的孩子是否为 null,如果是 说明当前前缀不存在,可以提前结束。如果不是 null,再判断当前节点是否是单词的结尾,如果是结尾直接将当前单词加入。

    由于递归过程中没有加路径,所以我们改造一下前缀树的节点,将单词直接存入节点,这样的话就可以直接取到了。

    干巴巴的文字可能不好理解,看一下下边的代码应该就明白了。

    结合代码就很好懂了,就是从每个位置对图做深度优先搜索,然后路径生成的字符串如果没有在前缀树中出现就提前结束,如果到了前缀树中某个单词的结束,就将当前单词加入即可。

    受到前边的题目思维的限制,只想到了解法一,优化的话也没有很成功。其实把思路倒过来,解法二也就可以出来了,很有意思。

    添加好友一起进步~

    如果想系统的学习数据结构和算法,强烈推荐一个我之前学过的课程,可以点击 这里 查看详情