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表示根节点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. 连接词相关推荐
- Leetcode刷题日记:21-25题篇
Leetcode刷题日记:21-25题篇 简介 题目: 21. 合并两个有序链表 22. 括号生成 23. 合并K个升序链表 24. 两两交换链表中的节点 25. K 个一组翻转链表 注 简介 这个系 ...
- 一个算法笨蛋的12月leetCode刷题日记
类似文章 一个算法笨蛋的2021年11月leetCode刷题日记 一个算法笨蛋的2021年12月leetCode刷题日记 一个算法笨蛋的2022年1月leetCode刷题日记 一个算法笨蛋的2022年 ...
- Leetcode刷题日记(十二)
又是老台词:欢迎大家来到一晚一度的leetcode刷题日记时间.今天我们来讲讲队列的问题,队列这方面的基础知识需要的同学到博主前面的文章找吧.队列这方面的问题平时博主也是接触得比较少的.下面是一道利用 ...
- 【LeetCode刷题日记】常用算法基础和理解及运用
在我们LeetCode刷题过程中,如果我们只是了解数据结构(数组,链表,数)的使用方法,那我们在面对复杂的题目时,是很难很好的解决问题的,因此我们要了解一些常用算法来帮助我们更好的解题. 递归和迭代 ...
- leetcode刷题日记(一)—— 数组
因为暑期实习找得很不顺利,感觉自身最大的问题体现在刷题量偏少,操作系统,数据库基础不好,所以现在决定写博客来记录整个过程,希望能找到大厂offer,如果不能找到的话也算是为秋招做准备. 剑指offer ...
- 石器时代 —— Leetcode刷题日记 (一 百大热题)
Date: 2019.10.22 - (C++ Version) 文章目录 All Labels: `热题100` L1 两数之和 L2 两数相加 暴力相加 递归 迭代 L3 无重复字符的最长子串 L ...
- [东哥的leetcode刷题日记] leetcode 278 :First Bad Version
leetcode 278 :First Bad Version 题目链接: https://leetcode-cn.com/problems/search-insert-position/ 难度: 简 ...
- LeetCode刷题日记盛最多水的容器
节后第一天,鉴于五一五天都没做过题,有点遗忘了,今天来看一道简单点的题,练下手. 先看下题: 给你 n 个非负整数 a1,a2,-,an,每个数代表坐标中的一个点 (i, ai) .在坐标内画 n 条 ...
- [东哥的leetcode刷题日记] leetcode 283 : Move Zeroes
leetcode 283 : Move Zeroes 题目链接: https://leetcode-cn.com/problems/move-zeroes/ 难度: 简单 归类 : 数组操作 题目: ...
- LeetCode刷题日记精选例题(解析+代码+链接)
文章目录 一.用栈模拟队列 二.用队列模拟栈 三.有效的括号 解法一 解法二 四.删除字符串中所有相邻重复项 五.逆波兰表达式求值 六.滑动窗口最大值 七.前k个高频元素 一.用栈模拟队列 因为队列先 ...
最新文章
- 强强联手!这所C9高校与西湖大学签约
- python 调用linux命令-Python调用Linux bash命令
- 电脑的添加删除系统组件使用方法
- 冲突域、广播域的通俗讲解
- servlet多线程
- mongodb中Gson和java##Bean对象转化类
- 数据结构之串:基本概念
- Mobx | 强大的状态管理工具 | 可以用Mobx来替代掉redux
- 一次简单易懂的多态重构实践,让你理解条件逻辑
- 计算机应用与推广,计算机在中小学教学中的推广和应用
- 查询数据库表大小sql
- 基于ARM的SoC设计入门
- 《因果推理原理:基础与学习算法》第一章 因果模型和统计模型
- springboot + quartz 分布式定时任务
- Speex的安装使用
- 移动硬盘写入数据报错“MS-DOS功能无效”,或移动硬盘内新建文件夹报错0x8000FFFF灾难性错误
- js点击第三方广告添加点击事件
- V2.0 版本的 《JavaGuide面试突击版》来啦!带着它的在线阅读版本来啦!
- 计算机修改人类记忆曲线,艾宾浩斯遗忘曲线和费曼技巧
- IDEA项目中配置Maven镜像源(下载源)
热门文章
- RabbitMQ小笔记
- java 字符串和整型的相互转换
- calender获取日期前几月_iOS时间,日期,星期等相关获取
- java 内部类_我有心上人了,Java内部类
- linux把profile文件删了怎么办,误删Profile后的处理
- 大师兄科研网_拜托啦,师兄!
- vscode写c++好吗_寒假实习简历你会写吗?四个问题帮你写好寒假实习简历
- c语言暂存按键数据变量,ET6218R按键检测程序
- Java中的几种设计模式:行为型模式
- 论文笔记_S2D.52_CMRNet++:在激光雷达地图中进行内参未知的相机的单目视觉定位