Given a list of strings words
representing an English Dictionary, find the longest word in words
that can be built one character at a time by other words in words
. If there is more than one possible answer, return the longest word with the smallest lexicographical order.
If there is no answer, return the empty string.
Example 1:
Input: words = ["w","wo","wor","worl", "world"] Output: "world" Explanation: The word "world" can be built one character at a time by "w", "wo", "wor", and "worl".
Example 2:
Input: words = ["a", "banana", "app", "appl", "ap", "apply", "apple"] Output: "apple" Explanation: Both "apply" and "apple" can be built from other words in the dictionary. However, "apple" is lexicographically smaller than "apply".
Note:
- All the strings in the input will only contain lowercase letters.
- The length of
words
will be in the range[1, 1000]
. - The length of
words[i]
will be in the range[1, 30]
.
词典中最长的单词。题意是给出一个字符串数组words组成的一本英语词典。从中找出最长的一个单词,该单词是由words词典中其他单词逐步添加一个字母组成。若其中有多个可行的答案,则返回答案中字典序最小的单词。若无答案,则返回空字符串。
我提供两种做法,一种暴力,一种是字典树 + BFS。
首先是暴力解,我们需要一个hashset记录单词。注意Arrays.sort()是可以对字母/单词排序的,所以我们用这个函数先对input array进行排序,这样字典序较小的单词会靠前。此时我们再次扫描input array,遍历每个单词,把每个单词加入一个hashset。加入之前判断
这个单词的长度是否为1 或者 hashset里面已经存在了这个单词除去最后一个字母的前缀(比如abc的话,我们去检查一下hashset里是否有ab)。这两个条件只要满足一个,就可以更新res的长度。
单词长度为1的话,只能是有一个空的前缀,但是越晚出现的单个字母,其字典序应该更大。这也就是为什么出现单个字母我们也需要更新res的原因。
时间O(n)
空间O(n) - hashset
Java实现
1 class Solution { 2 public String longestWord(String[] words) { 3 Arrays.sort(words); 4 HashSet<String> built = new HashSet<String>(); 5 String res = ""; 6 for (String w : words) { 7 if (w.length() == 1 || built.contains(w.substring(0, w.length() - 1))) { 8 res = w.length() > res.length() ? w : res; 9 built.add(w); 10 } 11 } 12 return res; 13 } 14 }
再来是字典树 + BFS的做法。这里我们还是自己写一个node class表示节点,其中有两个参数,一个是长度为26的数组表示字母,一个是最后node组成的单词word。遍历input数组,把每个单词都做成一个字典树的node。之后通过BFS的方式遍历queue中所有的node,返回字典序最小的结果。
时间O(n)
空间O(n) - node class
Java实现
1 class Solution { 2 // 字典树节点,每个节点代表一个字母 3 class Node { 4 // 该节点的下一个字母 5 Node[] children = new Node[26]; 6 // 如果是单词结尾,保存该单词,否则为空 7 String word; 8 } 9 10 // 定义字典树根节点 11 Node root = new Node(); 12 13 public String longestWord(String[] words) { 14 // 根节点默认单词为空 15 root.word = ""; 16 // 将每一个单词加入字典树 17 for (String s : words) { 18 Node node = root; 19 for (int i = 0; i < s.length(); i++) { 20 int c = s.charAt(i) - 'a'; 21 if (node.children[c] == null) { 22 node.children[c] = new Node(); 23 } 24 node = node.children[c]; 25 } 26 // 单词结尾时,将该单词保存至当前节点中 27 node.word = s; 28 } 29 // bfs 30 Queue<Node> q = new LinkedList<>(); 31 // bfs起点 32 q.offer(root); 33 // 返回结果 34 String res = ""; 35 while (q.size() > 0) { 36 int size = q.size(); 37 // 当前长度下字典顺序最小的单词 38 String smallestValid = ""; 39 while (size > 0) { 40 size--; 41 Node n = q.poll(); 42 // 记录当前长度下字典顺序最小的单词 43 if ("".equals(smallestValid)) { 44 smallestValid = n.word; 45 } 46 Node[] children = n.children; 47 for (int i = 0; i < 26; i++) { 48 // 如果子节点为空,或者子节点不是单词结尾,跳过 49 if (children[i] == null || children[i].word == null) { 50 continue; 51 } 52 // 将子节点添加到Queue中(子节点为下一个长度的单词) 53 q.offer(children[i]); 54 } 55 } 56 // 当前长度遍历完之后,将字典顺序最小的一个保存至返回结果 57 res = smallestValid; 58 } 59 return res; 60 } 61 }
相关题目
524. Longest Word in Dictionary through Deleting