[LeetCode] 720. Longest Word in Dictionary

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 中最长的一个单词,该单词是由 words 词典中其他单词逐步添加一个字母组成。
若其中有多个可行的答案,则返回答案中字典序最小的单词。若无答案,则返回空字符串。
题意是给出一个字符串数组 words 组成的一本英语词典。从中找出最长的一个单词,该单词是由 words 词典中其他单词逐步添加一个字母组成。若其中有多个可行的答案,则返回答案中字典序最小的单词。若无答案,则返回空字符串。

思路一,hashset

我们需要一个 hashset 记录单词。注意 Arrays.sort() 是可以对字母/单词排序的,所以我们用这个函数先对 input array 进行排序,这样字典序较小的单词会靠前。此时我们再次扫描 input array,遍历每个单词,把每个单词加入一个 hashset。加入之前判断

这个单词的长度是否为 1 或者 hashset 里面已经存在了这个单词除去最后一个字母的前缀(比如 abc 的话,我们去检查一下 hashset 里是否有 ab)。这两个条件只要满足一个,就可以更新 res 的长度。
单词长度为 1 的话,只能是有一个空的前缀,但是越晚出现的单个字母,其字典序应该更大。这也就是为什么出现单个字母我们也需要更新 res 的原因。

复杂度

时间O(nlogn)
空间O(n)

代码

Java实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public String longestWord(String[] words) {
Arrays.sort(words);
Set<String> set = new HashSet<String>();
String res = "";
for (String w : words) {
if (w.length() == 1 || set.contains(w.substring(0, w.length() - 1))) {
res = w.length() > res.length() ? w : res;
set.add(w);
}
}
return res;
}
}

思路二,字典树

再来是字典树 + BFS 的做法。这里我们还是自己写一个 node class 表示节点。遍历 input 数组,把每个单词都做成一个字典树的node。之后通过 BFS 的方式遍历 queue 中所有的 node,返回字典序最小的结果。

复杂度

时间O(n)
空间O(n) - node class

代码

Java实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
class Solution {
// 字典树节点,每个节点代表一个字母
class Node {
// 该节点的下一个字母
Node[] children = new Node[26];
// 如果是单词结尾,保存该单词,否则为空
String word;
}

// 定义字典树根节点
Node root = new Node();

public String longestWord(String[] words) {
// 根节点默认单词为空
root.word = "";
// 将每一个单词加入字典树
for (String s : words) {
Node node = root;
for (int i = 0; i < s.length(); i++) {
int c = s.charAt(i) - 'a';
if (node.children[c] == null) {
node.children[c] = new Node();
}
node = node.children[c];
}
// 单词结尾时,将该单词保存至当前节点中
node.word = s;
}
// bfs
Queue<Node> q = new LinkedList<>();
// bfs起点
q.offer(root);
// 返回结果
String res = "";
while (q.size() > 0) {
int size = q.size();
// 当前长度下字典顺序最小的单词
String smallestValid = "";
while (size > 0) {
size--;
Node n = q.poll();
// 记录当前长度下字典顺序最小的单词
if ("".equals(smallestValid)) {
smallestValid = n.word;
}
Node[] children = n.children;
for (int i = 0; i < 26; i++) {
// 如果子节点为空,或者子节点不是单词结尾,跳过
if (children[i] == null || children[i].word == null) {
continue;
}
// 将子节点添加到Queue中(子节点为下一个长度的单词)
q.offer(children[i]);
}
}
// 当前长度遍历完之后,将字典顺序最小的一个保存至返回结果
res = smallestValid;
}
return res;
}
}

相关题目

1
2
3
392. Is Subsequence
524. Longest Word in Dictionary through Deleting
720. Longest Word in Dictionary

[LeetCode] 720. Longest Word in Dictionary
https://shurui91.github.io/posts/2419185708.html
Author
Aaron Liu
Posted on
October 29, 2020
Licensed under