范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

LeetCode力扣官方题解472。连接词

  题目描述
  给你一个  不含重复  单词的字符串数组 words ,请你找出并返回 words 中的所有  连接词  。
  连接词  定义为:一个完全由给定数组中的至少两个较短单词组成的字符串。
  示例 1: 输入: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" 组成。
  示例 2: 输入:words = ["cat","dog","catdog"] 输出:["catdog"]
  提示: 1 <= words.length <=  10 ⁴ 0 <= words[i].length <= 1000 words[i] 仅由小写字母组成 0 <= sum(words[i].length) <=  10 ⁵
  解决方案
  前言
  本文的解法需要使用字典树。如果读者对字典树不了解,建议首先阅读「208. 实现 Trie (前缀树) 的官方题解」,在理解字典树的实现之后继续阅读本文。
  方法一:字典树 + 记忆化搜索
  思路与算法
  判断一个单词是不是连接词,需要判断这个单词是否完全由至少两个给定数组中的更短的非空单词(可以重复)组成。判断更短的单词是否在给定数组中,可以使用字典树实现。
  为了方便处理,首先将数组 words 按照字符串的长度递增的顺序排序,排序后可以确保当遍历到任意单词时,比该单词短的单词一定都已经遍历过,因此可以根据已经遍历过的全部单词判断当前单词是不是连接词。
  在将数组 words 排序之后,遍历数组,跳过空字符串,对于每个非空单词,判断该单词是不是连接词,如果是连接词则将该单词加入结果数组,如果不是连接词则将该单词加入字典树。
  判断一个单词是不是连接词的做法是在字典树中搜索。从该单词的第一个字符(即下标 0 处的字符)开始,在字典树中依次搜索每个字符对应的结点,可能有以下几种情况: 如果一个字符对应的结点是单词的结尾,则找到了一个更短的单词,从该字符的后一个字符开始搜索下一个更短的单词; 如果一个字符对应的结点在字典树中不存在,则当前的搜索结果失败,回到上一个单词的结尾继续搜索。
  如果找到一个更短的单词且这个更短的单词的最后一个字符是当前单词的最后一个字符,则当前单词是连接词。由于数组 words 中没有重复的单词,因此在判断一个单词是不是连接词时,该单词一定没有加入字典树,由此可以确保判断连接词的条件成立。
  由于一个连接词由多个更短的非空单词组成,如果存在一个较长的连接词的组成部分之一是一个较短的连接词,则一定可以将这个较短的连接词换成多个更短的非空单词,因此不需要将连接词加入字典树。
  为了降低时间复杂度,需要使用记忆化搜索。对于每个单词,创建与单词相同长度的数组记录该单词的每一个下标是否被访问过,然后进行记忆化搜索。搜索过程中,如果一个下标已经被访问过,则从该下标到末尾的部分一定不是由给定数组中的一个或多个非空单词组成(否则上次访问时已经可以知道当前单词是连接词),只有尚未访问过的下标才需要进行搜索。
  代码
  Python3 class Trie:     def __init__(self):         self.children = [None] * 26         self.isEnd = False      def insert(self, word: str):         node = self         for ch in word:             ch = ord(ch) - ord("a")             if not node.children[ch]:                 node.children[ch] = Trie()             node = node.children[ch]         node.isEnd = True      def dfs(self, word: str, start: int, vis: List[bool]) -> bool:         if start == len(word):             return True         if vis[start]:             return False         vis[start] = True         node = self         for i in range(start, len(word)):             node = node.children[ord(word[i]) - ord("a")]             if node is None:                 return False             if node.isEnd and self.dfs(word, i + 1, vis):                 return True         return False   class Solution:     def findAllConcatenatedWordsInADict(self, words: List[str]) -> List[str]:         words.sort(key=len)          ans = []         root = Trie()         for word in words:             if word == "":                 continue             if root.dfs(word, 0, [False] * len(word)):                 ans.append(word)             else:                 root.insert(word)         return ans
  C++ struct Trie {     bool isEnd;     vector children;     Trie() {         this->children = vector(26, nullptr);         this->isEnd = false;     } };  class Solution { public:     Trie * trie = new Trie();      vector findAllConcatenatedWordsInADict(vector& words) {         vector ans;         sort(words.begin(), words.end(), [&](const string & a, const string & b){             return a.size() < b.size();          });         for (int i = 0; i < words.size(); i++) {             string word = words[i];             if (word.size() == 0) {                 continue;             }             vector visited(word.size(), 0);             if (dfs(word, 0, visited)) {                 ans.emplace_back(word);             } else {                 insert(word);             }         }         return ans;     }      bool dfs(const string & word, int start, vector & visited) {         if (word.size() == start) {             return true;         }         if (visited[start]) {             return false;         }         visited[start] = true;         Trie * node = trie;         for (int i = start; i < word.size(); i++) {             char ch = word[i];             int index = ch - "a";             node = node->children[index];             if (node == nullptr) {                 return false;             }             if (node->isEnd) {                 if (dfs(word, i + 1, visited)) {                     return true;                 }             }         }         return false;     }      void insert(const string & word) {         Trie * node = trie;         for (int i = 0; i < word.size(); i++) {             char ch = word[i];             int index = ch - "a";             if (node->children[index] == nullptr) {                 node->children[index] = new Trie();             }             node = node->children[index];         }         node->isEnd = true;     } };
  Java class Solution {     Trie trie = new Trie();      public List findAllConcatenatedWordsInADict(String[] words) {         List ans = new ArrayList();         Arrays.sort(words, (a, b) -> a.length() - b.length());         for (int i = 0; i < words.length; i++) {             String word = words[i];             if (word.length() == 0) {                 continue;             }             boolean[] visited = new boolean[word.length()];             if (dfs(word, 0, visited)) {                 ans.add(word);             } else {                 insert(word);             }         }         return ans;     }      public boolean dfs(String word, int start, boolean[] visited) {         if (word.length() == start) {             return true;         }         if (visited[start]) {             return false;         }         visited[start] = true;         Trie node = trie;         for (int i = start; i < word.length(); i++) {             char ch = word.charAt(i);             int index = ch - "a";             node = node.children[index];             if (node == null) {                 return false;             }             if (node.isEnd) {                 if (dfs(word, i + 1, visited)) {                     return true;                 }             }         }         return false;     }          public void insert(String word) {         Trie node = trie;         for (int i = 0; i < word.length(); i++) {             char ch = word.charAt(i);             int index = ch - "a";             if (node.children[index] == null) {                 node.children[index] = new Trie();             }             node = node.children[index];         }         node.isEnd = true;     } }  class Trie {     Trie[] children;     boolean isEnd;      public Trie() {         children = new Trie[26];         isEnd = false;     } }
  Golang type trie struct {     children [26]*trie     isEnd    bool }  func (root *trie) insert(word string) {     node := root     for _, ch := range word {         ch -= "a"         if node.children[ch] == nil {             node.children[ch] = &trie{}         }         node = node.children[ch]     }     node.isEnd = true }  func (root *trie) dfs(vis []bool, word string) bool {     if word == "" {         return true     }     if vis[len(word)-1] {         return false     }     vis[len(word)-1] = true     node := root     for i, ch := range word {         node = node.children[ch-"a"]         if node == nil {             return false         }         if node.isEnd && root.dfs(vis, word[i+1:]) {             return true         }     }     return false }  func findAllConcatenatedWordsInADict(words []string) (ans []string) {     sort.Slice(words, func(i, j int) bool { return len(words[i]) < len(words[j]) })      root := &trie{}     for _, word := range words {         if word == "" {             continue         }         vis := make([]bool, len(word))         if root.dfs(vis, word) {             ans = append(ans, word)         } else {             root.insert(word)         }     }     return }
  C# public class Solution {     Trie trie = new Trie();      public IList FindAllConcatenatedWordsInADict(string[] words) {         IList ans = new List();         Array.Sort(words, (a, b) => a.Length - b.Length);         for (int i = 0; i < words.Length; i++) {             string word = words[i];             if (word.Length == 0) {                 continue;             }             bool[] visited = new bool[word.Length];             if (DFS(word, 0, visited)) {                 ans.Add(word);             } else {                 Insert(word);             }         }         return ans;     }      public bool DFS(string word, int start, bool[] visited) {         if (word.Length == start) {             return true;         }         if (visited[start]) {             return false;         }         visited[start] = true;         Trie node = trie;         for (int i = start; i < word.Length; i++) {             char ch = word[i];             int index = ch - "a";             node = node.children[index];             if (node == null) {                 return false;             }             if (node.isEnd) {                 if (DFS(word, i + 1, visited)) {                     return true;                 }             }         }         return false;     }          public void Insert(string word) {         Trie node = trie;         for (int i = 0; i < word.Length; i++) {             char ch = word[i];             int index = ch - "a";             if (node.children[index] == null) {                 node.children[index] = new Trie();             }             node = node.children[index];         }         node.isEnd = true;     } }  class Trie {     public Trie[] children;     public bool isEnd;      public Trie() {         children = new Trie[26];         isEnd = false;     } }
  C typedef struct Trie {     struct Trie * children[26];     bool isEnd; }Trie;  #define TRIE_INITIAL(node) do {      for (int i = 0; i < 26; ++i) {          (node)->children[i] = NULL;      }      (node)->isEnd = false;  }while(0);  static void freeTrie(Trie * node) {     if (NULL == node) {         return;     }     for (int i = 0; i < 26; ++i) {         if (node->children[i] != NULL) {             freeTrie(node->children[i]);         }     }     free(node); }  static int cmp(const void * pa, const void * pb){     int la = strlen(*(char **)pa);     int lb = strlen(*(char **)pb);     return la - lb; }  bool dfs(Trie * trie, const char * word, int wordSize, int start, int* visited) {     if (wordSize == start) {         return true;     }     if (visited[start]) {         return false;     }     visited[start] = 1;     Trie * node = trie;     for (int i = start; i < wordSize; i++) {         char ch = word[i];         int index = ch - "a";         node = node->children[index];         if (node == NULL) {             return false;         }         if (node->isEnd) {             if (dfs(trie, word, wordSize, i + 1, visited)) {                 return true;             }         }     }     return false; }  void insert(Trie * trie, const char * word, int wordSize) {     Trie * node = trie;     for (int i = 0; i < wordSize; i++) {         char ch = word[i];         int index = ch - "a";         if (node->children[index] == NULL) {             node->children[index] = (Trie *)malloc(sizeof(Trie));             TRIE_INITIAL(node->children[index]);         }         node = node->children[index];     }     node->isEnd = true; }  char ** findAllConcatenatedWordsInADict(char ** words, int wordsSize, int* returnSize){         int pos = 0;     char ** ans = (char **)malloc(sizeof(char *) * wordsSize);     Trie * trie = (Trie *)malloc(sizeof(Trie));      TRIE_INITIAL(trie);     qsort(words, wordsSize, sizeof(char *), cmp);     for (int i = 0; i < wordsSize; i++) {         int len = strlen(words[i]);         if (len == 0) {             continue;         }         int * visited = (int *)malloc(sizeof(int) * len);         memset(visited, 0, sizeof(int) * len);         if (dfs(trie, words[i], len, 0, visited)) {             ans[pos] = (char *)malloc(sizeof(char) * (len + 1));             strncpy(ans[pos], words[i], len);             ans[pos][len] = "";             pos++;         } else {             insert(trie, words[i], len);         }         free(visited);     }     freeTrie(trie);     *returnSize = pos;     return ans; }
  复杂度分析 时间复杂度:
  其中 n 是数组 words 的长度,li 是单词 words[i] 的长度。对数组 words 按照字符串的长度递增的顺序排序需要 O(nlog n) 的时间,判断单词 words[i] 是不是连接词的时间复杂度是 O(li)。  空间复杂度:
  其中 n 是数组 words 的长度,li 是单词 words[i] 的长度,S 是字符集,这道题中 S 为全部小写英语字母, S =26。空间复杂度主要取决于字典树,最坏情况下需要将所有的单词加入字典树。
  BY /
  本文作者:力扣
  声明:本文归"力扣"版权所有,如需转载请联系。

为何说科比3亿薪资是透支身体换来的,看了这5张照片你就懂科比的离开令人心痛,但是他影响力依旧巨大,特别是曼巴精神,更是激励了无数人。科比打球好看,数据又爆炸,他自然是联盟宠儿。既然是联盟的宠儿,商业价值肯定高,仅是工资20年就赚了超3。怀上三胎,身体状况良好铃木亚美宣布怀上三胎据日媒消息报道,歌手铃木亚美于4月5日通过Instagram社交平台宣布怀上三胎。铃木和粉丝们分享了这一喜讯本人成功怀上三胎,目前已有6个月的身孕。之前她还特地6岁女孩勇敢对霸凌说不,不好惹的气质,你家孩子有吗?胆子大外向的孩子和内向不爱说话的孩子,哪个不受人欺负?答案或许跟你想象的不一样,不好惹的气质,你家孩子有吗?我家儿子明明今年6岁了,每天在家里调皮捣蛋和一个小霸王一样,邻居家的女儿饭后应该如何养生?一做二不做,身体或许越来越好吃饭之后到底怎么做才最养生?这个问题一直困扰着很多人,有的人习惯饭后就躺着休息,也有的人为了防止积食,立刻开始运动究竟哪种方式是正确的呢?实际上,饭后要想让消化正常,身体健康,要记花开有时人无再少年春日百花盛开,各种裙装急不可待想上身,40的女人有长裙的优雅,半裙的随意,裤装的干练。背带裙却少有选择。总会觉得年纪大各种不适合,我也是如此,高中孩子的妈妈总觉得应该端庄持重然后青汪小菲妈妈生日,大S录视频送祝福,对前婆婆的称呼成焦点汪小菲跟大S去年11月份官宣离婚,如今两人正式分开已经近半年了,但是有关两人的前尘往事还是不绝于耳,这两日,大S一年前在粉丝群说的话被曝光,大S话语中透露儿子汪晞箖似乎对爸爸汪小菲大S教子有方,虽已新婚,仍然不忘带儿子给前婆婆庆祝生日理娱plus计划7日,是大S徐熙媛的前婆婆张兰的生日,但是令很多吃瓜群众都没有想到的是,新婚不久的大S竟然主动让她和汪小菲的儿子给奶奶打视频,祝福奶奶生日快乐。孙子自然乖巧可爱,视春天,孩子长个黄金期,晚餐别将就,多吃高钙食物,营养好吸收春天,孩子长个黄金期,晚餐别将就,多吃高钙食物,营养好吸收春季是孩子生长发育最好的时期,这个时候各位家长们,可别粗心大意了,平时一定要记得,多给孩子做点有营养的东西。春季孩子长个黄最常见的养胃食物,你知道几种?经济发展的快节奏,迫使现在的人跟上步伐,快餐应运而生。追求速度的同时,人的胃已经告急。十人十个胃口,却有八个胃不好,就是因为平时不注意养胃,造成其负担过重,继而引发胃炎胃溃疡胃癌等这几种食物有利于乙肝恢复,乙肝患者要了解如果乙肝患者能够给自己制定一份合理的膳食计划,在很大程度上都能够加快乙肝的恢复进程,今天小编就给大家推荐一些乙肝患者适合吃的食物以及平时患者需要注意的不该吃的食物,希望这些食物能更聚会时尿酸猛增,这几样食物吃了尿酸悄悄降下来节假日期间各种聚会不可避免,不管是为了工作还是为了沟通感情,聚会是最好的桥梁。尤其是亲朋好友相聚在一起,聚会一场接着一场,虽然有欢乐,但是背后也隐藏着健康危机。有不少人因为过多的聚
良好睡眠,健康同行良好睡眠健康同行2022年3月21日是第22个世界睡眠日,今年的主题是良好睡眠,健康同行,旨在进一步呼吁大众重视科学睡眠,重视睡眠健康。良好睡眠,可以恢复精神和解除疲劳,增强免疫力面条是糖尿病的加速剂?医生不止面条,这6物,尽量少吃夏方养生指南糖尿病是以血葡萄糖水平慢性增高为特征的代谢性疾病。糖尿病被称为富贵病,主要是由于人们饮食摄入不当,导致胰岛功能受损出现的慢性疾病。面条是生活中最常见的主食,面条中加入各5565岁是承上启下长寿关键期,请护好身体4处,做好5件事运动指导步入中年,你是不是感觉身体状态不如从前?正因如此,小动君赶紧给刚过50的爸妈准备了不少养生好物枸杞养生茶泡脚桶按摩椅图片来源shutterstock不过,咱中国人养生一向讲低压长期高于90,需要吃什么药?低压长期高于90,它一般有2种情况,一种是原发性的,一种是继发性的,继发性说的就是由于肾病内分泌疾病药物等原因导致的血压升高。这种高血压一般把相应的疾病治好,或停药以后,血压自己就心率多少是正常?高血压合并心率快,吃哪种药比较好?普通人群对正常心率的认知,普遍认为心率停留在60100次分之间,都是属于正常心率范围,实际上这个观念是错误的,所谓心率在60100次分之间属于正常心率,是早年间的一种专家共识,并没高血压是如何引起的?可能与这七方面原因有关,尽量避开高血压对许多朋友来说已经不再陌生了,临床上这种疾病产生会引起许多身体不适反应,对工作和生活造成影响。毕竟这是一种以动脉压升高为特征的综合征,发病原因和不良的生活习惯饮食不合理有关。血压要知晓,降压要达标我国现患高血压人数约3。3亿,随着人口老龄化和城镇化的加速,我国高血压的患病率仍呈升高趋势。高血压可导致心脑肾血管眼底等器官损伤导致并发症。早发现早干预早达标是防治高血压及其发症的长期吃阿卡波糖,会出现哪些副作用?该如何应对?早知道,早受益阿卡波糖是葡萄糖苷酶抑制剂,通过抑制碳水化合物在小肠上部的吸收,来达到减少餐后血糖生成,降低餐后血糖的目的,所以特别适合餐后血糖高,以米饭馒头面条等碳水化合物为主要食物的高血糖患者比乡巴佬还好吃的卤蛋,做法简单,口感Q弹,卤香浓郁,吃不腻小时候最爱吃的零食就是乡巴佬卤蛋了,QQ弹弹搭配咸香入味儿的口感,真的是怎么都吃不够。每次买上一个都是小口小口的吃,吃完还会念念不忘,想着下次有了零花钱还得再买上几个。童年的味道之8道家常菜做法,4荤4素,简单易学,营养美味,非常适合上班族上班辛苦一天,下班到家吃什么好呢?下面,就和大家分享8道家常菜的做法,简单易学,营养美味,有喜欢的朋友们赶紧收藏起来吧,再也不用发愁晚饭吃什么了。红烧鱼1。准备食材准备一条鲤鱼,已安徽95后烧鸡西施,一天卖7万三代祖传手艺,不靠老汤味道一样美在北方的山东对于鸡有一种特别的喜爱,也有一种说法叫无鸡不成宴,不管是招待亲朋好友还是大摆筵席都离不开一道鸡肉的美味,山东的炒鸡遍布大街小巷,烧鸡也是畅销全国,在安徽也有一家做烧鸡的