解題說明
Longest Word in Dictionary
題目描述:給定一個字串陣列 words,找出其中最長的單詞,使得該單詞可以由陣列中其他單詞逐字元「累積建構」而成——也就是說,該單詞的每個前綴(長度 1、2、3……直到完整單詞)都必須出現在 words 中。若有多個最長單詞,回傳字典序最小者。
解題思路:最優雅的解法是使用 Trie。先將所有單詞插入 Trie,並在每個單詞結尾節點標記 is_end = true。接著從根節點開始做 BFS 或 DFS,只沿「is_end = true」的節點走——這保證路徑上每一個前綴都在原陣列中出現過。過程中記錄到達的最深節點所代表的單詞,即為答案。
另一種簡潔方法:先將 words 排序(排序後較短的前綴一定先出現),再用 HashSet 逐一確認每個單詞的長度 - 1 前綴是否在集合中,是則加入集合並嘗試更新答案。排序確保「前綴先到」,HashSet 確保前綴存在性,兩者結合即可線性掃描完成。
C++ 解法
複雜度分析
時間複雜度:O(N × L × log N)——排序需 O(N log N) 次比較,每次字串比較最多 O(L);隨後線性掃描 O(N × L)(substr 和 HashSet 操作均 O(L))。整體由排序主導:O(N × L × log N)。
空間複雜度:O(N × L)——HashSet 最壞情況下儲存所有單詞,每個長度最多 L;排序就地完成不需額外空間(忽略遞迴 stack)。
虛擬碼
1. Sort words by length ascending; ties broken by lexicographic order.
2. Initialize a HashSet built = {""} (empty string as base).
3. Initialize result = "".
4. For each word in the sorted words:
a. Compute prefix = word[0 .. len-2].
b. If prefix is in built:
- Add word to built.
- If len(word) > len(result), update result = word.
5. Return result.其他解法
方法一:Trie + BFS/DFS
將所有單詞插入 Trie,標記每個單詞的結尾節點。從根節點出發,只遍歷 is_end = true 的節點(保證路徑上每個前綴都在陣列中),記錄最深路徑對應的單詞。時間複雜度 O(N × L),空間 O(N × L × 26)。實作稍複雜但不需排序,適合多次查詢的場景。
方法二:暴力 HashSet 逐字元驗證
將所有單詞存入 HashSet,對每個單詞 w,逐一檢查 w[0..0]、w[0..1]……w[0..len-2] 是否都在 HashSet 中,全部滿足才是候選答案。時間複雜度 O(N × L²)(每個單詞有 O(L) 個前綴,每次 substr + 查詢 O(L)),比排序法慢,但無需排序、程式碼直觀。
方法三:排序 + Trie 合併 先排序,再用 Trie 取代 HashSet 儲存已建構的單詞。前綴查詢在 Trie 中為 O(L) 且共享節點,理論上節省記憶體,但實作複雜度增加,一般不推薦。
延伸思考
- 若允許跳過某些前綴(不要求每個長度的前綴都存在),問題變為「最長可從陣列中某些單詞拼接而成的單詞」,該如何修改演算法?
- 若
words陣列非常大(百萬級),排序成為瓶頸,有什麼線性時間替代方案?(提示:考慮 radix sort 或 Trie 直接 BFS) - 若要找出「所有」滿足條件的最長單詞(而非字典序最小的一個),如何修改回傳值和判斷邏輯?