題目描述
這是 LeetCode 上的 720. 詞典中最長的單詞 ,難度為 簡單。
Tag : 「模拟」、「哈希表」、「字典樹」
給出一個字元串數組
words
組成的一本英語詞典。傳回
words
中最長的一個單詞,該單詞是由
words
詞典中其他單詞逐漸添加一個字母組成。
若其中有多個可行的答案,則傳回答案中字典序最小的單詞。若無答案,則傳回空字元串。
示例 1:
輸入:words = ["w","wo","wor","worl", "world"]
輸出:"world"
解釋: 單詞"world"可由"w", "wo", "wor", 和 "worl"逐漸添加一個字母組成。
示例 2:
輸入:words = ["a", "banana", "app", "appl", "ap", "apply", "apple"]
輸出:"apple"
解釋:"apply" 和 "apple" 都能由詞典中的單詞組成。但是 "apple" 的字典序小于 "apply"
提示:
- 所有輸入的字元串
模拟
資料範圍很小,我們可以直接模拟來做。
先将所有的 存入
Set
集合,友善後續可以近似 查詢某個子串是否存在
周遊 數組(題目沒有說 不重複,是以最好周遊剛剛預處理的
Set
集合),判斷每個
不算剪枝效果,該做法計算量不超過 ,可以過。
代碼:
class Solution {
public String longestWord(String[] words) {
String ans = "";
Set<String> set = new HashSet<>();
for (String s : words) set.add(s);
for (String s : set) {
int n = s.length(), m = ans.length();
if (n < m) continue;
if (n == m && s.compareTo(ans) > 0) continue;
boolean ok = true;
for (int i = 1; i <= n && ok; i++) {
String sub = s.substring(0, i);
if (!set.contains(sub)) ok = false;
}
if (ok) ans = s;
}
return
- 時間複雜度:預處理
集合複雜度近似;判斷某個是否合法需要判斷所有子串是否均在中,複雜度為,其中為字元串長度,處理的過程還使用到Set
操作,其複雜度為,其中和為參與比較的兩字元串長度,該操作相比于生成子串可忽略,而對于一個長度為的字元串而言,生成其所有的子串的計算量為首項為,末項為,公差為的等差數列求和結果。整體複雜度為compareTo
- 空間複雜度:
Trie
上述解法中「枚舉某個 的所有子串,并判斷子串是否在
不了解「Trie / 字典樹」的同學可以看前置 🧀:字典樹入門。裡面通過圖例展示了字典樹基本形态,以及提供了「數組實作」和「TrieNode 實作」兩種方式,還有「數組大小估算方式」和「Trie 應用面」介紹。
回到本題,起始先将所有的
對于某個 而言,其能成為「合法單詞」的充要條件為:
一些細節:為了防止每個樣例都 大數組,我們使用
new
進行優化,并在跑樣例前進行相應的清理工作。
static
代碼:
class Solution {
static int N = 30010, M = 26;
static int[][] tr = new int[N][M];
static boolean[] isEnd = new boolean[N];
static int idx = 0;
void add(String s) {
int p = 0, n = s.length();
for (int i = 0; i < n; i++) {
int u = s.charAt(i) - 'a';
if (tr[p][u] == 0) tr[p][u] = ++idx;
p = tr[p][u];
}
isEnd[p] = true;
}
boolean query(String s) {
int p = 0, n = s.length();
for (int i = 0; i < n; i++) {
int u = s.charAt(i) - 'a';
p = tr[p][u];
if (!isEnd[p]) return false;
}
return true;
}
public String longestWord(String[] words) {
Arrays.fill(isEnd, false);
for (int i = 0; i <= idx; i++) Arrays.fill(tr[i], 0);
idx = 0;
String ans = "";
for (String s : words) add(s);
for (String s : words) {
int n = s.length(), m = ans.length();
if (n < m) continue;
if (n == m && s.compareTo(ans) > 0) continue;
if (query(s)) ans = s;
}
return
- 時間複雜度:将所有存入字典樹的複雜度為;查詢每個是否合法的複雜度為,其中為目前長度。整體複雜度為
- 空間複雜度:
最後
這是我們「刷穿 LeetCode」系列文章的第
No.720
篇,系列開始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道題目,部分是有鎖題,我們将先把所有不帶鎖的題目刷完。
在這個系列文章裡面,除了講解解題思路以外,還會盡可能給出最為簡潔的代碼。如果涉及通解還會相應的代碼模闆。