leetcode刷题日记-472. 连接词

  • 题目描述:
    给你一个 不含重复 单词的字符串数组 words ,请你找出并返回 words 中的所有连接词 。
    连接词 定义为:一个完全由给定数组中的至少两个较短单词组成的字符串。

  • 示例:
    输入:words = [“cat”,“cats”,“catsdogcats”,“dog”,“dogcatsdog”,“hippopotamuses”,“rat”,“ratcatdogcat”]
    输出:[“catsdogcats”,“dogcatsdog”,“ratcatdogcat”]
    解释:“catsdogcats” 由 “cats”, “dog” 和 “cats” 组成;
    “dogcatsdog” 由 “dog”, “cats” 和 “dog” 组成;
    “ratcatdogcat” 由 “rat”, “cat”, “dog” 和 “cat” 组成。
    输入:words = [“cat”,“dog”,“catdog”]
    输出:[“catdog”]

  • 解析:这个题目说难很难,说不难也不难。如果你深刻理解字典树的原理,那么这题就很简单,只要实现了一颗字典树,然后再加上一个简单的深度优先遍历,这个题目就解决了。如果不知道字典树,那么这个题目基本很难解出来。
      首先说说字典树吧,字典树(Trie),就是一个以字母作为每个节点值的一种树,一条路径表示一个单词,如下所示。懂了下图,其实也就够了,现在我们来考虑怎么实现这个字典树。
    在这里插入图片描述

  • 图片来源:字典树(Trie)详解

  • 第一步:节点的构成,假如我们所有的单词均由小写字母构成,那么从root节点开始,每个节点都有26个子节点,表示a-z,除了这个我们考虑到,一条路径就是一个单词,因此路径是有限的,我们还需要为节点指定一个状态,表示到这个节点,单词路径是否已经到了尽头。如对上图,对于路径a-b-c,构成了以个单词abc,那么c就应该有一个状态,指示到c节点,该单词路径结束,所以我们的Trie的构造函数就出来了:

    def __init__(self):
        self.children = [None]*26 #表示26个小写字母
        self.isEnd = False #表示该节点是否是单词的最后一个字母
  • 第二步:树的构成。我们再观察上图,给定一个单词"abcd",如何将其加入Trie呢?只要大家对二叉树有过了解,这里应该不难,就是一个简单的遍历+深度优先赋值,这里我们用ord© - ord(‘a’)的值来表示该字母c对应的哪一个节点,即self.children[0]表示"a",self.children[1]表示"b",以此类推。实现代码如下:
    def insert(self, word):
        node = self #self表示根节点root
        for c in word:
            cV = ord(c) - ord('a')
            if not node.children[cV]:
                node.children[cV] = Trie()
            node = node.children[cV]
        node.isEnd = True  
  • 第三步:判断单词是否由该数的单词组合而成。我们可以这么考虑,假如我们的树已经有了cat、dog两个单词路径,判断catdog是不是该树的单词产生,那么我们可以将catdog分解成两个部分,即cat和dog,并给定一个中间变量temp记录已经遍历过的字符,如果node.isEnd = True 同时temp=len(word)那么就说明该word由Trie树中的单词组成。换句话说,就是一个单词路径走完,再回到根节点走下一条单词路径,直到顺利走完整个word,这个时候才能返回True,其他情况全部是False,代码如下:
    def dfs(self, word, temp):
        if temp == len(word): 
            return True
        node = self
        for i in range(temp, len(word)):
            node = node.children[ord(word[i]) - ord('a')]
            if not node:
                return False
            if node.isEnd and self.dfs(word, i+1):
                return True
        return False
  • 我们再回到本题,给你一个不含重复 单词的字符串数组 words ,请你找出并返回 words 中的所有连接词。由于本题不含重复单词,我们考虑到只有“长”单词才有可能是组合词,那么这个“长”如何定义呢?答案就是对words字符串数组,按照长度进行排序即可,因为如果该单词是组合词,那么他一定是由在他之前的单词组合而成。这里可以采用反证法证明,如果组成该单词a的某一个单词b,在该单词之后,那么b的长度一定大于a,如果b的长度大于a,那么b一定不可能是a的子词。所以,基于字典树的解题思路就有了,当该字符是组合词的时候,记录,如果不是组合词,将该词添加进字典树,所有代码如下:
class Trie:
    def __init__(self):
        self.children = [None]*26  #表示26个小写字母
        self.isEnd = False #表示该节点是否是单词的最后一个字母

    def insert(self, word):
        node = self #self表示根节点root
        for c in word:
            cV = ord(c) - ord('a')
            if not node.children[cV]:
                node.children[cV] = Trie()
            node = node.children[cV]
        node.isEnd = True

    def dfs(self, word, temp):
        if temp == len(word):
            return True
        node = self
        for i in range(temp, len(word)):
            node = node.children[ord(word[i]) - ord('a')]
            if not node:
                return False
            if node.isEnd and self.dfs(word, i+1):
                return True
        return False

class Solution:
    def findAllConcatenatedWordsInADict(self, words: List[str]) -> List[str]:
        """
        给你一个 不含重复 单词的字符串数组 words ,请你找出并返回 words 中的所有连
        接词 
        >>>words = ["cat","dog","catdog"]
        >>>self.findAllConcatenatedWordsInADict(words)
        >>>"catdog"]
        """
        words.sort(key = len)
        ans = []
        root = Trie()
        for word in words:
            if word == "":
                continue
            if root.dfs(word, 0):
                ans.append(word)
            else:
                root.insert(word)
        return ans
  • 如果大家觉得有帮助,欢迎点个免费的赞,谢谢!在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lemon_tttea

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值