From f9031932e071693d5fc161089fb37b107f6478cf Mon Sep 17 00:00:00 2001 From: yanglbme Date: Fri, 14 Feb 2025 17:12:42 +0800 Subject: [PATCH] feat: add solutions to lcci problem: No.17.15 No.17.15.Longest Word --- lcci/17.15.Longest Word/README.md | 314 +++++++++++++------------ lcci/17.15.Longest Word/README_EN.md | 314 +++++++++++++------------ lcci/17.15.Longest Word/Solution.cpp | 27 +++ lcci/17.15.Longest Word/Solution.go | 56 +---- lcci/17.15.Longest Word/Solution.java | 53 +---- lcci/17.15.Longest Word/Solution.py | 51 +--- lcci/17.15.Longest Word/Solution.rs | 28 +++ lcci/17.15.Longest Word/Solution.swift | 58 ++--- lcci/17.15.Longest Word/Solution.ts | 26 ++ 9 files changed, 451 insertions(+), 476 deletions(-) create mode 100644 lcci/17.15.Longest Word/Solution.cpp create mode 100644 lcci/17.15.Longest Word/Solution.rs create mode 100644 lcci/17.15.Longest Word/Solution.ts diff --git a/lcci/17.15.Longest Word/README.md b/lcci/17.15.Longest Word/README.md index a9840705c9c6a..0f6dffe5c3aa8 100644 --- a/lcci/17.15.Longest Word/README.md +++ b/lcci/17.15.Longest Word/README.md @@ -32,117 +32,79 @@ edit_url: https://github.com/doocs/leetcode/edit/main/lcci/17.15.Longest%20Word/ -### 方法一:前缀树 + DFS +### 方法一:哈希表 + 排序 + DFS + +注意,题目中,每个单词实际上允许重复使用。 + +我们可以用一个哈希表 $\textit{s}$ 存储所有单词,然后对单词按照长度降序排序,如果长度相同,按照字典序升序排序。 + +接下来,我们遍历排序后的单词列表,对于每个单词 $\textit{w}$,我们先将其从哈希表 $\textit{s}$ 中移除,然后使用深度优先搜索 $\textit{dfs}$ 判断 $\textit{w}$ 是否可以由其他单词组成,如果可以,返回 $\textit{w}$。 + +函数 $\textit{dfs}$ 的执行逻辑如下: + +- 如果 $\textit{w}$ 为空,返回 $\text{true}$; +- 遍历 $\textit{w}$ 的所有前缀,如果前缀在哈希表 $\textit{s}$ 中且 $\textit{dfs}$ 返回 $\text{true}$,则返回 $\text{true}$; +- 如果没有符合条件的前缀,返回 $\text{false}$。 + +如果没有找到符合条件的单词,返回空字符串。 + +时间复杂度 $O(m \times n \times \log n + n \times 2^M)$,空间复杂度 $O(m \times n)$。其中 $n$ 和 $m$ 分别为单词列表的长度和单词的平均长度,而 $M$ 为最长单词的长度。 #### Python3 ```python -class Trie: - def __init__(self): - self.children = [None] * 26 - self.is_end = False - - def insert(self, word): - node = self - for c in word: - idx = ord(c) - ord('a') - if node.children[idx] is None: - node.children[idx] = Trie() - node = node.children[idx] - node.is_end = True - - def search(self, word): - node = self - for c in word: - idx = ord(c) - ord('a') - if node.children[idx] is None: - return False - node = node.children[idx] - return node.is_end - - class Solution: def longestWord(self, words: List[str]) -> str: - def cmp(a, b): - if len(a) != len(b): - return len(a) - len(b) - return -1 if a > b else 1 - - def dfs(w): - return not w or any( - trie.search(w[:i]) and dfs(w[i:]) for i in range(1, len(w) + 1) - ) - - words.sort(key=cmp_to_key(cmp)) - trie = Trie() - ans = "" + def dfs(w: str) -> bool: + if not w: + return True + for k in range(1, len(w) + 1): + if w[:k] in s and dfs(w[k:]): + return True + return False + + s = set(words) + words.sort(key=lambda x: (-len(x), x)) for w in words: + s.remove(w) if dfs(w): - ans = w - trie.insert(w) - return ans + return w + return "" ``` #### Java ```java -class Trie { - Trie[] children = new Trie[26]; - boolean isEnd; - - void insert(String word) { - Trie node = this; - for (char c : word.toCharArray()) { - c -= 'a'; - if (node.children[c] == null) { - node.children[c] = new Trie(); - } - node = node.children[c]; - } - node.isEnd = true; - } - - boolean search(String word) { - Trie node = this; - for (char c : word.toCharArray()) { - c -= 'a'; - if (node.children[c] == null) { - return false; - } - node = node.children[c]; - } - return node.isEnd; - } -} - class Solution { - private Trie trie = new Trie(); + private Set s = new HashSet<>(); public String longestWord(String[] words) { + for (String w : words) { + s.add(w); + } Arrays.sort(words, (a, b) -> { if (a.length() != b.length()) { - return a.length() - b.length(); + return b.length() - a.length(); } - return b.compareTo(a); + return a.compareTo(b); }); - String ans = ""; for (String w : words) { + s.remove(w); if (dfs(w)) { - ans = w; + return w; } - trie.insert(w); } - return ans; + return ""; } private boolean dfs(String w) { - if ("".equals(w)) { + if (w.length() == 0) { return true; } - for (int i = 1; i <= w.length(); ++i) { - if (trie.search(w.substring(0, i)) && dfs(w.substring(i))) { + for (int k = 1; k <= w.length(); ++k) { + if (s.contains(w.substring(0, k)) && dfs(w.substring(k))) { return true; } } @@ -151,131 +113,171 @@ class Solution { } ``` -#### Go - -```go -type Trie struct { - children [26]*Trie - isEnd bool -} +#### C++ -func newTrie() *Trie { - return &Trie{} -} -func (this *Trie) insert(word string) { - node := this - for _, c := range word { - c -= 'a' - if node.children[c] == nil { - node.children[c] = newTrie() - } - node = node.children[c] - } - node.isEnd = true -} +```cpp +class Solution { +public: + string longestWord(vector& words) { + unordered_set s(words.begin(), words.end()); + ranges::sort(words, [&](const string& a, const string& b) { + return a.size() > b.size() || (a.size() == b.size() && a < b); + }); + auto dfs = [&](this auto&& dfs, string w) -> bool { + if (w.empty()) { + return true; + } + for (int k = 1; k <= w.size(); ++k) { + if (s.contains(w.substr(0, k)) && dfs(w.substr(k))) { + return true; + } + } + return false; + }; + for (const string& w : words) { + s.erase(w); + if (dfs(w)) { + return w; + } + } + return ""; + } +}; +``` -func (this *Trie) search(word string) bool { - node := this - for _, c := range word { - c -= 'a' - if node.children[c] == nil { - return false - } - node = node.children[c] - } - return node.isEnd -} +#### Go +```go func longestWord(words []string) string { + s := map[string]bool{} + for _, w := range words { + s[w] = true + } sort.Slice(words, func(i, j int) bool { - a, b := words[i], words[j] - if len(a) != len(b) { - return len(a) < len(b) - } - return a > b + return len(words[i]) > len(words[j]) || (len(words[i]) == len(words[j]) && words[i] < words[j]) }) - trie := newTrie() var dfs func(string) bool dfs = func(w string) bool { if len(w) == 0 { return true } - for i := 1; i <= len(w); i++ { - if trie.search(w[:i]) && dfs(w[i:]) { + for k := 1; k <= len(w); k++ { + if s[w[:k]] && dfs(w[k:]) { return true } } return false } - ans := "" for _, w := range words { + s[w] = false if dfs(w) { - ans = w + return w } - trie.insert(w) } - return ans + return "" } ``` -#### Swift +#### TypeScript -```swift -class Trie { - var children = [Trie?](repeating: nil, count: 26) - var isEnd = false - - func insert(_ word: String) { - var node = self - for ch in word { - let index = Int(ch.asciiValue! - Character("a").asciiValue!) - if node.children[index] == nil { - node.children[index] = Trie() +```ts +function longestWord(words: string[]): string { + const s = new Set(words); + + words.sort((a, b) => (a.length === b.length ? a.localeCompare(b) : b.length - a.length)); + + const dfs = (w: string): boolean => { + if (w === '') { + return true; + } + for (let k = 1; k <= w.length; ++k) { + if (s.has(w.substring(0, k)) && dfs(w.substring(k))) { + return true; } - node = node.children[index]! } - node.isEnd = true + return false; + }; + + for (const w of words) { + s.delete(w); + if (dfs(w)) { + return w; + } } - func search(_ word: String) -> Bool { - var node = self - for ch in word { - let index = Int(ch.asciiValue! - Character("a").asciiValue!) - if node.children[index] == nil { - return false + return ''; +} +``` + +#### Rust + +```rust +use std::collections::HashSet; + +impl Solution { + pub fn longest_word(words: Vec) -> String { + let mut s: HashSet = words.iter().cloned().collect(); + let mut words = words; + words.sort_by(|a, b| b.len().cmp(&a.len()).then(a.cmp(b))); + + fn dfs(w: String, s: &mut HashSet) -> bool { + if w.is_empty() { + return true; } - node = node.children[index]! + for k in 1..=w.len() { + if s.contains(&w[0..k]) && dfs(w[k..].to_string(), s) { + return true; + } + } + false } - return node.isEnd + for w in words { + s.remove(&w); + if dfs(w.clone(), &mut s) { + return w; + } + } + String::new() } } +``` + +#### Swift +```swift class Solution { func longestWord(_ words: [String]) -> String { - var words = words.sorted(by: { $0.count < $1.count || ($0.count == $1.count && $0 > $1) }) - let trie = Trie() + var s: Set = Set(words) + var words = words + words.sort { (a, b) -> Bool in + if a.count == b.count { + return a < b + } else { + return a.count > b.count + } + } - var dfs: ((String) -> Bool)! - dfs = { w in + func dfs(_ w: String) -> Bool { if w.isEmpty { return true } - for i in 1...w.count { - if trie.search(String(w.prefix(i))) && dfs(String(w.suffix(w.count - i))) { + for k in 1...w.count { + let prefix = String(w.prefix(k)) + if s.contains(prefix) && dfs(String(w.dropFirst(k))) { return true } } return false } - var ans = "" for w in words { + s.remove(w) if dfs(w) { - ans = w + return w } - trie.insert(w) } - return ans + + return "" } } ``` diff --git a/lcci/17.15.Longest Word/README_EN.md b/lcci/17.15.Longest Word/README_EN.md index 7d5dcf7f14dec..131326adf233f 100644 --- a/lcci/17.15.Longest Word/README_EN.md +++ b/lcci/17.15.Longest Word/README_EN.md @@ -41,117 +41,79 @@ edit_url: https://github.com/doocs/leetcode/edit/main/lcci/17.15.Longest%20Word/ -### Solution 1 +### Solution 1: Hash Table + Sorting + DFS + +Note that in the problem, each word can actually be reused. + +We can use a hash table $\textit{s}$ to store all the words, then sort the words in descending order of length, and if the lengths are the same, sort them in ascending lexicographical order. + +Next, we iterate through the sorted list of words. For each word $\textit{w}$, we first remove it from the hash table $\textit{s}$, then use depth-first search $\textit{dfs}$ to determine if $\textit{w}$ can be composed of other words. If it can, we return $\textit{w}$. + +The execution logic of the function $\textit{dfs}$ is as follows: + +- If $\textit{w}$ is empty, return $\text{true}$; +- Iterate through all prefixes of $\textit{w}$. If a prefix is in the hash table $\textit{s}$ and $\textit{dfs}$ returns $\text{true}$, then return $\text{true}$; +- If no prefix meets the condition, return $\text{false}$. + +If no word meets the condition, return an empty string. + +The time complexity is $O(m \times n \times \log n + n \times 2^M)$, and the space complexity is $O(m \times n)$. Here, $n$ and $m$ are the length of the word list and the average length of the words, respectively, and $M$ is the length of the longest word. #### Python3 ```python -class Trie: - def __init__(self): - self.children = [None] * 26 - self.is_end = False - - def insert(self, word): - node = self - for c in word: - idx = ord(c) - ord('a') - if node.children[idx] is None: - node.children[idx] = Trie() - node = node.children[idx] - node.is_end = True - - def search(self, word): - node = self - for c in word: - idx = ord(c) - ord('a') - if node.children[idx] is None: - return False - node = node.children[idx] - return node.is_end - - class Solution: def longestWord(self, words: List[str]) -> str: - def cmp(a, b): - if len(a) != len(b): - return len(a) - len(b) - return -1 if a > b else 1 - - def dfs(w): - return not w or any( - trie.search(w[:i]) and dfs(w[i:]) for i in range(1, len(w) + 1) - ) - - words.sort(key=cmp_to_key(cmp)) - trie = Trie() - ans = "" + def dfs(w: str) -> bool: + if not w: + return True + for k in range(1, len(w) + 1): + if w[:k] in s and dfs(w[k:]): + return True + return False + + s = set(words) + words.sort(key=lambda x: (-len(x), x)) for w in words: + s.remove(w) if dfs(w): - ans = w - trie.insert(w) - return ans + return w + return "" ``` #### Java ```java -class Trie { - Trie[] children = new Trie[26]; - boolean isEnd; - - void insert(String word) { - Trie node = this; - for (char c : word.toCharArray()) { - c -= 'a'; - if (node.children[c] == null) { - node.children[c] = new Trie(); - } - node = node.children[c]; - } - node.isEnd = true; - } - - boolean search(String word) { - Trie node = this; - for (char c : word.toCharArray()) { - c -= 'a'; - if (node.children[c] == null) { - return false; - } - node = node.children[c]; - } - return node.isEnd; - } -} - class Solution { - private Trie trie = new Trie(); + private Set s = new HashSet<>(); public String longestWord(String[] words) { + for (String w : words) { + s.add(w); + } Arrays.sort(words, (a, b) -> { if (a.length() != b.length()) { - return a.length() - b.length(); + return b.length() - a.length(); } - return b.compareTo(a); + return a.compareTo(b); }); - String ans = ""; for (String w : words) { + s.remove(w); if (dfs(w)) { - ans = w; + return w; } - trie.insert(w); } - return ans; + return ""; } private boolean dfs(String w) { - if ("".equals(w)) { + if (w.length() == 0) { return true; } - for (int i = 1; i <= w.length(); ++i) { - if (trie.search(w.substring(0, i)) && dfs(w.substring(i))) { + for (int k = 1; k <= w.length(); ++k) { + if (s.contains(w.substring(0, k)) && dfs(w.substring(k))) { return true; } } @@ -160,131 +122,171 @@ class Solution { } ``` -#### Go - -```go -type Trie struct { - children [26]*Trie - isEnd bool -} +#### C++ -func newTrie() *Trie { - return &Trie{} -} -func (this *Trie) insert(word string) { - node := this - for _, c := range word { - c -= 'a' - if node.children[c] == nil { - node.children[c] = newTrie() - } - node = node.children[c] - } - node.isEnd = true -} +```cpp +class Solution { +public: + string longestWord(vector& words) { + unordered_set s(words.begin(), words.end()); + ranges::sort(words, [&](const string& a, const string& b) { + return a.size() > b.size() || (a.size() == b.size() && a < b); + }); + auto dfs = [&](this auto&& dfs, string w) -> bool { + if (w.empty()) { + return true; + } + for (int k = 1; k <= w.size(); ++k) { + if (s.contains(w.substr(0, k)) && dfs(w.substr(k))) { + return true; + } + } + return false; + }; + for (const string& w : words) { + s.erase(w); + if (dfs(w)) { + return w; + } + } + return ""; + } +}; +``` -func (this *Trie) search(word string) bool { - node := this - for _, c := range word { - c -= 'a' - if node.children[c] == nil { - return false - } - node = node.children[c] - } - return node.isEnd -} +#### Go +```go func longestWord(words []string) string { + s := map[string]bool{} + for _, w := range words { + s[w] = true + } sort.Slice(words, func(i, j int) bool { - a, b := words[i], words[j] - if len(a) != len(b) { - return len(a) < len(b) - } - return a > b + return len(words[i]) > len(words[j]) || (len(words[i]) == len(words[j]) && words[i] < words[j]) }) - trie := newTrie() var dfs func(string) bool dfs = func(w string) bool { if len(w) == 0 { return true } - for i := 1; i <= len(w); i++ { - if trie.search(w[:i]) && dfs(w[i:]) { + for k := 1; k <= len(w); k++ { + if s[w[:k]] && dfs(w[k:]) { return true } } return false } - ans := "" for _, w := range words { + s[w] = false if dfs(w) { - ans = w + return w } - trie.insert(w) } - return ans + return "" } ``` -#### Swift +#### TypeScript -```swift -class Trie { - var children = [Trie?](repeating: nil, count: 26) - var isEnd = false - - func insert(_ word: String) { - var node = self - for ch in word { - let index = Int(ch.asciiValue! - Character("a").asciiValue!) - if node.children[index] == nil { - node.children[index] = Trie() +```ts +function longestWord(words: string[]): string { + const s = new Set(words); + + words.sort((a, b) => (a.length === b.length ? a.localeCompare(b) : b.length - a.length)); + + const dfs = (w: string): boolean => { + if (w === '') { + return true; + } + for (let k = 1; k <= w.length; ++k) { + if (s.has(w.substring(0, k)) && dfs(w.substring(k))) { + return true; } - node = node.children[index]! } - node.isEnd = true + return false; + }; + + for (const w of words) { + s.delete(w); + if (dfs(w)) { + return w; + } } - func search(_ word: String) -> Bool { - var node = self - for ch in word { - let index = Int(ch.asciiValue! - Character("a").asciiValue!) - if node.children[index] == nil { - return false + return ''; +} +``` + +#### Rust + +```rust +use std::collections::HashSet; + +impl Solution { + pub fn longest_word(words: Vec) -> String { + let mut s: HashSet = words.iter().cloned().collect(); + let mut words = words; + words.sort_by(|a, b| b.len().cmp(&a.len()).then(a.cmp(b))); + + fn dfs(w: String, s: &mut HashSet) -> bool { + if w.is_empty() { + return true; } - node = node.children[index]! + for k in 1..=w.len() { + if s.contains(&w[0..k]) && dfs(w[k..].to_string(), s) { + return true; + } + } + false } - return node.isEnd + for w in words { + s.remove(&w); + if dfs(w.clone(), &mut s) { + return w; + } + } + String::new() } } +``` + +#### Swift +```swift class Solution { func longestWord(_ words: [String]) -> String { - var words = words.sorted(by: { $0.count < $1.count || ($0.count == $1.count && $0 > $1) }) - let trie = Trie() + var s: Set = Set(words) + var words = words + words.sort { (a, b) -> Bool in + if a.count == b.count { + return a < b + } else { + return a.count > b.count + } + } - var dfs: ((String) -> Bool)! - dfs = { w in + func dfs(_ w: String) -> Bool { if w.isEmpty { return true } - for i in 1...w.count { - if trie.search(String(w.prefix(i))) && dfs(String(w.suffix(w.count - i))) { + for k in 1...w.count { + let prefix = String(w.prefix(k)) + if s.contains(prefix) && dfs(String(w.dropFirst(k))) { return true } } return false } - var ans = "" for w in words { + s.remove(w) if dfs(w) { - ans = w + return w } - trie.insert(w) } - return ans + + return "" } } ``` diff --git a/lcci/17.15.Longest Word/Solution.cpp b/lcci/17.15.Longest Word/Solution.cpp new file mode 100644 index 0000000000000..19b158b023c7d --- /dev/null +++ b/lcci/17.15.Longest Word/Solution.cpp @@ -0,0 +1,27 @@ +class Solution { +public: + string longestWord(vector& words) { + unordered_set s(words.begin(), words.end()); + ranges::sort(words, [&](const string& a, const string& b) { + return a.size() > b.size() || (a.size() == b.size() && a < b); + }); + auto dfs = [&](this auto&& dfs, string w) -> bool { + if (w.empty()) { + return true; + } + for (int k = 1; k <= w.size(); ++k) { + if (s.contains(w.substr(0, k)) && dfs(w.substr(k))) { + return true; + } + } + return false; + }; + for (const string& w : words) { + s.erase(w); + if (dfs(w)) { + return w; + } + } + return ""; + } +}; diff --git a/lcci/17.15.Longest Word/Solution.go b/lcci/17.15.Longest Word/Solution.go index 2a6dbd07cf5a4..321fb05d318ae 100644 --- a/lcci/17.15.Longest Word/Solution.go +++ b/lcci/17.15.Longest Word/Solution.go @@ -1,62 +1,28 @@ -type Trie struct { - children [26]*Trie - isEnd bool -} - -func newTrie() *Trie { - return &Trie{} -} -func (this *Trie) insert(word string) { - node := this - for _, c := range word { - c -= 'a' - if node.children[c] == nil { - node.children[c] = newTrie() - } - node = node.children[c] - } - node.isEnd = true -} - -func (this *Trie) search(word string) bool { - node := this - for _, c := range word { - c -= 'a' - if node.children[c] == nil { - return false - } - node = node.children[c] - } - return node.isEnd -} - func longestWord(words []string) string { + s := map[string]bool{} + for _, w := range words { + s[w] = true + } sort.Slice(words, func(i, j int) bool { - a, b := words[i], words[j] - if len(a) != len(b) { - return len(a) < len(b) - } - return a > b + return len(words[i]) > len(words[j]) || (len(words[i]) == len(words[j]) && words[i] < words[j]) }) - trie := newTrie() var dfs func(string) bool dfs = func(w string) bool { if len(w) == 0 { return true } - for i := 1; i <= len(w); i++ { - if trie.search(w[:i]) && dfs(w[i:]) { + for k := 1; k <= len(w); k++ { + if s[w[:k]] && dfs(w[k:]) { return true } } return false } - ans := "" for _, w := range words { + s[w] = false if dfs(w) { - ans = w + return w } - trie.insert(w) } - return ans -} \ No newline at end of file + return "" +} diff --git a/lcci/17.15.Longest Word/Solution.java b/lcci/17.15.Longest Word/Solution.java index 2d6e2d40bd4c3..e7bbcc380a592 100644 --- a/lcci/17.15.Longest Word/Solution.java +++ b/lcci/17.15.Longest Word/Solution.java @@ -1,61 +1,34 @@ -class Trie { - Trie[] children = new Trie[26]; - boolean isEnd; - - void insert(String word) { - Trie node = this; - for (char c : word.toCharArray()) { - c -= 'a'; - if (node.children[c] == null) { - node.children[c] = new Trie(); - } - node = node.children[c]; - } - node.isEnd = true; - } - - boolean search(String word) { - Trie node = this; - for (char c : word.toCharArray()) { - c -= 'a'; - if (node.children[c] == null) { - return false; - } - node = node.children[c]; - } - return node.isEnd; - } -} - class Solution { - private Trie trie = new Trie(); + private Set s = new HashSet<>(); public String longestWord(String[] words) { + for (String w : words) { + s.add(w); + } Arrays.sort(words, (a, b) -> { if (a.length() != b.length()) { - return a.length() - b.length(); + return b.length() - a.length(); } - return b.compareTo(a); + return a.compareTo(b); }); - String ans = ""; for (String w : words) { + s.remove(w); if (dfs(w)) { - ans = w; + return w; } - trie.insert(w); } - return ans; + return ""; } private boolean dfs(String w) { - if ("".equals(w)) { + if (w.length() == 0) { return true; } - for (int i = 1; i <= w.length(); ++i) { - if (trie.search(w.substring(0, i)) && dfs(w.substring(i))) { + for (int k = 1; k <= w.length(); ++k) { + if (s.contains(w.substring(0, k)) && dfs(w.substring(k))) { return true; } } return false; } -} \ No newline at end of file +} diff --git a/lcci/17.15.Longest Word/Solution.py b/lcci/17.15.Longest Word/Solution.py index 5a5b69545a1a2..c2dd7b8387c09 100644 --- a/lcci/17.15.Longest Word/Solution.py +++ b/lcci/17.15.Longest Word/Solution.py @@ -1,44 +1,17 @@ -class Trie: - def __init__(self): - self.children = [None] * 26 - self.is_end = False - - def insert(self, word): - node = self - for c in word: - idx = ord(c) - ord('a') - if node.children[idx] is None: - node.children[idx] = Trie() - node = node.children[idx] - node.is_end = True - - def search(self, word): - node = self - for c in word: - idx = ord(c) - ord('a') - if node.children[idx] is None: - return False - node = node.children[idx] - return node.is_end - - class Solution: def longestWord(self, words: List[str]) -> str: - def cmp(a, b): - if len(a) != len(b): - return len(a) - len(b) - return -1 if a > b else 1 - - def dfs(w): - return not w or any( - trie.search(w[:i]) and dfs(w[i:]) for i in range(1, len(w) + 1) - ) + def dfs(w: str) -> bool: + if not w: + return True + for k in range(1, len(w) + 1): + if w[:k] in s and dfs(w[k:]): + return True + return False - words.sort(key=cmp_to_key(cmp)) - trie = Trie() - ans = "" + s = set(words) + words.sort(key=lambda x: (-len(x), x)) for w in words: + s.remove(w) if dfs(w): - ans = w - trie.insert(w) - return ans + return w + return "" diff --git a/lcci/17.15.Longest Word/Solution.rs b/lcci/17.15.Longest Word/Solution.rs new file mode 100644 index 0000000000000..068124b25c26a --- /dev/null +++ b/lcci/17.15.Longest Word/Solution.rs @@ -0,0 +1,28 @@ +use std::collections::HashSet; + +impl Solution { + pub fn longest_word(words: Vec) -> String { + let mut s: HashSet = words.iter().cloned().collect(); + let mut words = words; + words.sort_by(|a, b| b.len().cmp(&a.len()).then(a.cmp(b))); + + fn dfs(w: String, s: &mut HashSet) -> bool { + if w.is_empty() { + return true; + } + for k in 1..=w.len() { + if s.contains(&w[0..k]) && dfs(w[k..].to_string(), s) { + return true; + } + } + false + } + for w in words { + s.remove(&w); + if dfs(w.clone(), &mut s) { + return w; + } + } + String::new() + } +} diff --git a/lcci/17.15.Longest Word/Solution.swift b/lcci/17.15.Longest Word/Solution.swift index f05b1fc22864c..008d82149d0be 100644 --- a/lcci/17.15.Longest Word/Solution.swift +++ b/lcci/17.15.Longest Word/Solution.swift @@ -1,57 +1,35 @@ -class Trie { - var children = [Trie?](repeating: nil, count: 26) - var isEnd = false - - func insert(_ word: String) { - var node = self - for ch in word { - let index = Int(ch.asciiValue! - Character("a").asciiValue!) - if node.children[index] == nil { - node.children[index] = Trie() +class Solution { + func longestWord(_ words: [String]) -> String { + var s: Set = Set(words) + var words = words + words.sort { (a, b) -> Bool in + if a.count == b.count { + return a < b + } else { + return a.count > b.count } - node = node.children[index]! } - node.isEnd = true - } - func search(_ word: String) -> Bool { - var node = self - for ch in word { - let index = Int(ch.asciiValue! - Character("a").asciiValue!) - if node.children[index] == nil { - return false - } - node = node.children[index]! - } - return node.isEnd - } -} - -class Solution { - func longestWord(_ words: [String]) -> String { - var words = words.sorted(by: { $0.count < $1.count || ($0.count == $1.count && $0 > $1) }) - let trie = Trie() - - var dfs: ((String) -> Bool)! - dfs = { w in + func dfs(_ w: String) -> Bool { if w.isEmpty { return true } - for i in 1...w.count { - if trie.search(String(w.prefix(i))) && dfs(String(w.suffix(w.count - i))) { + for k in 1...w.count { + let prefix = String(w.prefix(k)) + if s.contains(prefix) && dfs(String(w.dropFirst(k))) { return true } } return false } - - var ans = "" + for w in words { + s.remove(w) if dfs(w) { - ans = w + return w } - trie.insert(w) } - return ans + + return "" } } diff --git a/lcci/17.15.Longest Word/Solution.ts b/lcci/17.15.Longest Word/Solution.ts new file mode 100644 index 0000000000000..1dc4862412162 --- /dev/null +++ b/lcci/17.15.Longest Word/Solution.ts @@ -0,0 +1,26 @@ +function longestWord(words: string[]): string { + const s = new Set(words); + + words.sort((a, b) => (a.length === b.length ? a.localeCompare(b) : b.length - a.length)); + + const dfs = (w: string): boolean => { + if (w === '') { + return true; + } + for (let k = 1; k <= w.length; ++k) { + if (s.has(w.substring(0, k)) && dfs(w.substring(k))) { + return true; + } + } + return false; + }; + + for (const w of words) { + s.delete(w); + if (dfs(w)) { + return w; + } + } + + return ''; +}