• 题目描述:
    给你一个 不含重复 单词的字符串数组 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表示根节点rootfor 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 Truenode = selffor i in range(temp, len(word)):node = node.children[ord(word[i]) - ord('a')]if not node:return Falseif node.isEnd and self.dfs(word, i+1):return Truereturn 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表示根节点rootfor c in word:cV = ord(c) - ord('a')if not node.children[cV]:node.children[cV] = Trie()node = node.children[cV]node.isEnd = Truedef dfs(self, word, temp):if temp == len(word):return Truenode = selffor i in range(temp, len(word)):node = node.children[ord(word[i]) - ord('a')]if not node:return Falseif node.isEnd and self.dfs(word, i+1):return Truereturn Falseclass 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 == "":continueif root.dfs(word, 0):ans.append(word)else:root.insert(word)return ans
  • 如果大家觉得有帮助,欢迎点个免费的赞,谢谢!

leetcode刷题日记-472. 连接词相关推荐

  1. Leetcode刷题日记:21-25题篇

    Leetcode刷题日记:21-25题篇 简介 题目: 21. 合并两个有序链表 22. 括号生成 23. 合并K个升序链表 24. 两两交换链表中的节点 25. K 个一组翻转链表 注 简介 这个系 ...

  2. 一个算法笨蛋的12月leetCode刷题日记

    类似文章 一个算法笨蛋的2021年11月leetCode刷题日记 一个算法笨蛋的2021年12月leetCode刷题日记 一个算法笨蛋的2022年1月leetCode刷题日记 一个算法笨蛋的2022年 ...

  3. Leetcode刷题日记(十二)

    又是老台词:欢迎大家来到一晚一度的leetcode刷题日记时间.今天我们来讲讲队列的问题,队列这方面的基础知识需要的同学到博主前面的文章找吧.队列这方面的问题平时博主也是接触得比较少的.下面是一道利用 ...

  4. 【LeetCode刷题日记】常用算法基础和理解及运用

    在我们LeetCode刷题过程中,如果我们只是了解数据结构(数组,链表,数)的使用方法,那我们在面对复杂的题目时,是很难很好的解决问题的,因此我们要了解一些常用算法来帮助我们更好的解题. 递归和迭代 ...

  5. leetcode刷题日记(一)—— 数组

    因为暑期实习找得很不顺利,感觉自身最大的问题体现在刷题量偏少,操作系统,数据库基础不好,所以现在决定写博客来记录整个过程,希望能找到大厂offer,如果不能找到的话也算是为秋招做准备. 剑指offer ...

  6. 石器时代 —— Leetcode刷题日记 (一 百大热题)

    Date: 2019.10.22 - (C++ Version) 文章目录 All Labels: `热题100` L1 两数之和 L2 两数相加 暴力相加 递归 迭代 L3 无重复字符的最长子串 L ...

  7. [东哥的leetcode刷题日记] leetcode 278 :First Bad Version

    leetcode 278 :First Bad Version 题目链接: https://leetcode-cn.com/problems/search-insert-position/ 难度: 简 ...

  8. LeetCode刷题日记盛最多水的容器

    节后第一天,鉴于五一五天都没做过题,有点遗忘了,今天来看一道简单点的题,练下手. 先看下题: 给你 n 个非负整数 a1,a2,-,an,每个数代表坐标中的一个点 (i, ai) .在坐标内画 n 条 ...

  9. [东哥的leetcode刷题日记] leetcode 283 : Move Zeroes

    leetcode 283 : Move Zeroes 题目链接: https://leetcode-cn.com/problems/move-zeroes/ 难度: 简单 归类 : 数组操作 题目: ...

  10. LeetCode刷题日记精选例题(解析+代码+链接)

    文章目录 一.用栈模拟队列 二.用队列模拟栈 三.有效的括号 解法一 解法二 四.删除字符串中所有相邻重复项 五.逆波兰表达式求值 六.滑动窗口最大值 七.前k个高频元素 一.用栈模拟队列 因为队列先 ...

最新文章

  1. 强强联手!这所C9高校与西湖大学签约
  2. python 调用linux命令-Python调用Linux bash命令
  3. 电脑的添加删除系统组件使用方法
  4. 冲突域、广播域的通俗讲解
  5. servlet多线程
  6. mongodb中Gson和java##Bean对象转化类
  7. 数据结构之串:基本概念
  8. Mobx | 强大的状态管理工具 | 可以用Mobx来替代掉redux
  9. 一次简单易懂的多态重构实践,让你理解条件逻辑
  10. 计算机应用与推广,计算机在中小学教学中的推广和应用
  11. 查询数据库表大小sql
  12. 基于ARM的SoC设计入门
  13. 《因果推理原理:基础与学习算法》第一章 因果模型和统计模型
  14. springboot + quartz 分布式定时任务
  15. Speex的安装使用
  16. 移动硬盘写入数据报错“MS-DOS功能无效”,或移动硬盘内新建文件夹报错0x8000FFFF灾难性错误
  17. js点击第三方广告添加点击事件
  18. V2.0 版本的 《JavaGuide面试突击版》来啦!带着它的在线阅读版本来啦!
  19. 计算机修改人类记忆曲线,艾宾浩斯遗忘曲线和费曼技巧
  20. IDEA项目中配置Maven镜像源(下载源)

热门文章

  1. RabbitMQ小笔记
  2. java 字符串和整型的相互转换
  3. calender获取日期前几月_iOS时间,日期,星期等相关获取
  4. java 内部类_我有心上人了,Java内部类
  5. linux把profile文件删了怎么办,误删Profile后的处理
  6. 大师兄科研网_拜托啦,师兄!
  7. vscode写c++好吗_寒假实习简历你会写吗?四个问题帮你写好寒假实习简历
  8. c语言暂存按键数据变量,ET6218R按键检测程序
  9. Java中的几种设计模式:行为型模式
  10. 论文笔记_S2D.52_CMRNet++:在激光雷达地图中进行内参未知的相机的单目视觉定位