diff --git a/solution/0700-0799/0720.Longest Word in Dictionary/README.md b/solution/0700-0799/0720.Longest Word in Dictionary/README.md index 8f441c16a01eb..2b5851f0e2a22 100644 --- a/solution/0700-0799/0720.Longest Word in Dictionary/README.md +++ b/solution/0700-0799/0720.Longest Word in Dictionary/README.md @@ -41,7 +41,7 @@ tags:
 输入:words = ["a", "banana", "app", "appl", "ap", "apply", "apple"]
 输出:"apple"
-解释:"apply" 和 "apple" 都能由词典中的单词组成。但是 "apple" 的字典序小于 "apply" 
+解释:"apply" 和 "apple" 都能由词典中的单词组成。但是 "apple" 的字典序小于 "apply"
 

 

@@ -60,121 +60,202 @@ tags: -### 方法一:哈希表 +### 方法一:字典树 -用哈希表存放所有单词。遍历这些单词,找出**长度最长且字典序最小**的单词。 +我们可以使用字典树来存储所有的单词,然后遍历所有的单词,判断当前单词是否可以由字典树中的其他单词逐步添加一个字母组成,找出满足条件的最长的,且字典序最小的单词。 + +时间复杂度 $O(L)$,空间复杂度 $O(L)$,其中 $L$ 是所有单词的长度之和。 #### Python3 ```python +class Trie: + def __init__(self): + self.children: List[Optional[Trie]] = [None] * 26 + self.is_end = False + + def insert(self, w: str): + node = self + for c in w: + 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, w: str) -> bool: + node = self + for c in w: + idx = ord(c) - ord("a") + if node.children[idx] is None: + return False + node = node.children[idx] + if not node.is_end: + return False + return True + + class Solution: def longestWord(self, words: List[str]) -> str: - cnt, ans = 0, '' - s = set(words) - for w in s: - n = len(w) - if all(w[:i] in s for i in range(1, n)): - if cnt < n: - cnt, ans = n, w - elif cnt == n and w < ans: - ans = w + trie = Trie() + for w in words: + trie.insert(w) + ans = "" + for w in words: + if trie.search(w) and ( + len(ans) < len(w) or (len(ans) == len(w) and ans > w) + ): + ans = w return ans ``` #### Java ```java -class Solution { - private Set s; - - public String longestWord(String[] words) { - s = new HashSet<>(Arrays.asList(words)); - int cnt = 0; - String ans = ""; - for (String w : s) { - int n = w.length(); - if (check(w)) { - if (cnt < n) { - cnt = n; - ans = w; - } else if (cnt == n && w.compareTo(ans) < 0) { - ans = w; - } +class Trie { + private Trie[] children = new Trie[26]; + private boolean isEnd = false; + + public void insert(String w) { + Trie node = this; + for (char c : w.toCharArray()) { + int idx = c - 'a'; + if (node.children[idx] == null) { + node.children[idx] = new Trie(); } + node = node.children[idx]; } - return ans; + node.isEnd = true; } - private boolean check(String word) { - for (int i = 1, n = word.length(); i < n; ++i) { - if (!s.contains(word.substring(0, i))) { + public boolean search(String w) { + Trie node = this; + for (char c : w.toCharArray()) { + int idx = c - 'a'; + if (node.children[idx] == null || !node.children[idx].isEnd) { return false; } + node = node.children[idx]; } return true; } } + +class Solution { + public String longestWord(String[] words) { + Trie trie = new Trie(); + for (String w : words) { + trie.insert(w); + } + String ans = ""; + for (String w : words) { + if (trie.search(w) + && (ans.length() < w.length() + || (ans.length() == w.length() && w.compareTo(ans) < 0))) { + ans = w; + } + } + return ans; + } +} ``` #### C++ ```cpp -class Solution { +class Trie { public: - string longestWord(vector& words) { - unordered_set s(words.begin(), words.end()); - int cnt = 0; - string ans = ""; - for (auto w : s) { - int n = w.size(); - if (check(w, s)) { - if (cnt < n) { - cnt = n; - ans = w; - } else if (cnt == n && w < ans) - ans = w; + Trie* children[26] = {nullptr}; + bool isEnd = false; + + void insert(const string& w) { + Trie* node = this; + for (char c : w) { + int idx = c - 'a'; + if (node->children[idx] == nullptr) { + node->children[idx] = new Trie(); } + node = node->children[idx]; } - return ans; + node->isEnd = true; } - bool check(string& word, unordered_set& s) { - for (int i = 1, n = word.size(); i < n; ++i) - if (!s.count(word.substr(0, i))) + bool search(const string& w) { + Trie* node = this; + for (char c : w) { + int idx = c - 'a'; + if (node->children[idx] == nullptr || !node->children[idx]->isEnd) { return false; + } + node = node->children[idx]; + } return true; } }; + +class Solution { +public: + string longestWord(vector& words) { + Trie trie; + for (const string& w : words) { + trie.insert(w); + } + + string ans = ""; + for (const string& w : words) { + if (trie.search(w) && (ans.length() < w.length() || (ans.length() == w.length() && w < ans))) { + ans = w; + } + } + return ans; + } +}; ``` #### Go ```go +type Trie struct { + children [26]*Trie + isEnd bool +} + +func (t *Trie) insert(w string) { + node := t + for i := 0; i < len(w); i++ { + idx := w[i] - 'a' + if node.children[idx] == nil { + node.children[idx] = &Trie{} + } + node = node.children[idx] + } + node.isEnd = true +} + +func (t *Trie) search(w string) bool { + node := t + for i := 0; i < len(w); i++ { + idx := w[i] - 'a' + if node.children[idx] == nil || !node.children[idx].isEnd { + return false + } + node = node.children[idx] + } + return true +} + func longestWord(words []string) string { - s := make(map[string]bool) + trie := &Trie{} for _, w := range words { - s[w] = true + trie.insert(w) } - cnt := 0 + ans := "" - check := func(word string) bool { - for i, n := 1, len(word); i < n; i++ { - if !s[word[:i]] { - return false - } - } - return true - } - for w, _ := range s { - n := len(w) - if check(w) { - if cnt < n { - cnt, ans = n, w - } else if cnt == n && w < ans { - ans = w - } + for _, w := range words { + if trie.search(w) && (len(ans) < len(w) || (len(ans) == len(w) && w < ans)) { + ans = w } } return ans @@ -184,63 +265,165 @@ func longestWord(words []string) string { #### TypeScript ```ts -function longestWord(words: string[]): string { - words.sort((a, b) => { - const n = a.length; - const m = b.length; - if (n === m) { - return a < b ? -1 : 1; - } - return m - n; - }); - for (const word of words) { - let isPass = true; - for (let i = 1; i <= word.length; i++) { - if (!words.includes(word.slice(0, i))) { - isPass = false; - break; +class Trie { + children: (Trie | null)[] = new Array(26).fill(null); + isEnd: boolean = false; + + insert(w: string): void { + let node: Trie = this; + for (let i = 0; i < w.length; i++) { + const idx: number = w.charCodeAt(i) - 'a'.charCodeAt(0); + if (node.children[idx] === null) { + node.children[idx] = new Trie(); } + node = node.children[idx]!; } - if (isPass) { - return word; + node.isEnd = true; + } + + search(w: string): boolean { + let node: Trie = this; + for (let i = 0; i < w.length; i++) { + const idx: number = w.charCodeAt(i) - 'a'.charCodeAt(0); + if (node.children[idx] === null || !node.children[idx]!.isEnd) { + return false; + } + node = node.children[idx]!; } + return true; } - return ''; +} + +function longestWord(words: string[]): string { + const trie = new Trie(); + for (const w of words) { + trie.insert(w); + } + + let ans = ''; + for (const w of words) { + if (trie.search(w) && (ans.length < w.length || (ans.length === w.length && w < ans))) { + ans = w; + } + } + return ans; } ``` #### Rust ```rust -impl Solution { - pub fn longest_word(mut words: Vec) -> String { - words.sort_unstable_by(|a, b| (b.len(), a).cmp(&(a.len(), b))); - for word in words.iter() { - let mut is_pass = true; - for i in 1..=word.len() { - if !words.contains(&word[..i].to_string()) { - is_pass = false; - break; - } +struct Trie { + children: [Option>; 26], + is_end: bool, +} + +impl Trie { + fn new() -> Self { + Trie { + children: Default::default(), + is_end: false, + } + } + + fn insert(&mut self, w: &str) { + let mut node = self; + for c in w.chars() { + let idx = (c as usize) - ('a' as usize); + if node.children[idx].is_none() { + node.children[idx] = Some(Box::new(Trie::new())); + } + node = node.children[idx].as_mut().unwrap(); + } + node.is_end = true; + } + + fn search(&self, w: &str) -> bool { + let mut node = self; + for c in w.chars() { + let idx = (c as usize) - ('a' as usize); + if node.children[idx].is_none() || !node.children[idx].as_ref().unwrap().is_end { + return false; } - if is_pass { - return word.clone(); + node = node.children[idx].as_ref().unwrap(); + } + true + } +} + +impl Solution { + pub fn longest_word(words: Vec) -> String { + let mut trie = Trie::new(); + for w in &words { + trie.insert(w); + } + + let mut ans = String::new(); + for w in words { + if trie.search(&w) && (ans.len() < w.len() || (ans.len() == w.len() && w < ans)) { + ans = w; } } - String::new() + ans } } ``` - +#### JavaScript + +```js +/** + * @param {string[]} words + * @return {string} + */ +var longestWord = function (words) { + const trie = new Trie(); + for (const w of words) { + trie.insert(w); + } - + let ans = ''; + for (const w of words) { + if (trie.search(w) && (ans.length < w.length || (ans.length === w.length && w < ans))) { + ans = w; + } + } + return ans; +}; - +class Trie { + constructor() { + this.children = Array(26).fill(null); + this.isEnd = false; + } -### 方法二:排序 + insert(w) { + let node = this; + for (let i = 0; i < w.length; i++) { + const idx = w.charCodeAt(i) - 'a'.charCodeAt(0); + if (node.children[idx] === null) { + node.children[idx] = new Trie(); + } + node = node.children[idx]; + } + node.isEnd = true; + } + + search(w) { + let node = this; + for (let i = 0; i < w.length; i++) { + const idx = w.charCodeAt(i) - 'a'.charCodeAt(0); + if (node.children[idx] === null || !node.children[idx].isEnd) { + return false; + } + node = node.children[idx]; + } + return true; + } +} +``` -优先返回符合条件、**长度最长且字典序最小**的单词,那么可以进行依照该规则,先对 `words` 进行排序,免去多个结果之间的比较。 + diff --git a/solution/0700-0799/0720.Longest Word in Dictionary/README_EN.md b/solution/0700-0799/0720.Longest Word in Dictionary/README_EN.md index 886cf6301b6d7..83a5493fded69 100644 --- a/solution/0700-0799/0720.Longest Word in Dictionary/README_EN.md +++ b/solution/0700-0799/0720.Longest Word in Dictionary/README_EN.md @@ -58,119 +58,202 @@ tags: -### Solution 1 +### Solution 1: Trie + +We can use a trie to store all the words, then traverse all the words to determine if the current word can be formed by adding one letter at a time from other words in the trie. Find the longest word that meets the condition and has the smallest lexicographical order. + +The time complexity is $O(L)$, and the space complexity is $O(L)$, where $L$ is the sum of the lengths of all words. #### Python3 ```python +class Trie: + def __init__(self): + self.children: List[Optional[Trie]] = [None] * 26 + self.is_end = False + + def insert(self, w: str): + node = self + for c in w: + 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, w: str) -> bool: + node = self + for c in w: + idx = ord(c) - ord("a") + if node.children[idx] is None: + return False + node = node.children[idx] + if not node.is_end: + return False + return True + + class Solution: def longestWord(self, words: List[str]) -> str: - cnt, ans = 0, '' - s = set(words) - for w in s: - n = len(w) - if all(w[:i] in s for i in range(1, n)): - if cnt < n: - cnt, ans = n, w - elif cnt == n and w < ans: - ans = w + trie = Trie() + for w in words: + trie.insert(w) + ans = "" + for w in words: + if trie.search(w) and ( + len(ans) < len(w) or (len(ans) == len(w) and ans > w) + ): + ans = w return ans ``` #### Java ```java -class Solution { - private Set s; - - public String longestWord(String[] words) { - s = new HashSet<>(Arrays.asList(words)); - int cnt = 0; - String ans = ""; - for (String w : s) { - int n = w.length(); - if (check(w)) { - if (cnt < n) { - cnt = n; - ans = w; - } else if (cnt == n && w.compareTo(ans) < 0) { - ans = w; - } +class Trie { + private Trie[] children = new Trie[26]; + private boolean isEnd = false; + + public void insert(String w) { + Trie node = this; + for (char c : w.toCharArray()) { + int idx = c - 'a'; + if (node.children[idx] == null) { + node.children[idx] = new Trie(); } + node = node.children[idx]; } - return ans; + node.isEnd = true; } - private boolean check(String word) { - for (int i = 1, n = word.length(); i < n; ++i) { - if (!s.contains(word.substring(0, i))) { + public boolean search(String w) { + Trie node = this; + for (char c : w.toCharArray()) { + int idx = c - 'a'; + if (node.children[idx] == null || !node.children[idx].isEnd) { return false; } + node = node.children[idx]; } return true; } } + +class Solution { + public String longestWord(String[] words) { + Trie trie = new Trie(); + for (String w : words) { + trie.insert(w); + } + String ans = ""; + for (String w : words) { + if (trie.search(w) + && (ans.length() < w.length() + || (ans.length() == w.length() && w.compareTo(ans) < 0))) { + ans = w; + } + } + return ans; + } +} ``` #### C++ ```cpp -class Solution { +class Trie { public: - string longestWord(vector& words) { - unordered_set s(words.begin(), words.end()); - int cnt = 0; - string ans = ""; - for (auto w : s) { - int n = w.size(); - if (check(w, s)) { - if (cnt < n) { - cnt = n; - ans = w; - } else if (cnt == n && w < ans) - ans = w; + Trie* children[26] = {nullptr}; + bool isEnd = false; + + void insert(const string& w) { + Trie* node = this; + for (char c : w) { + int idx = c - 'a'; + if (node->children[idx] == nullptr) { + node->children[idx] = new Trie(); } + node = node->children[idx]; } - return ans; + node->isEnd = true; } - bool check(string& word, unordered_set& s) { - for (int i = 1, n = word.size(); i < n; ++i) - if (!s.count(word.substr(0, i))) + bool search(const string& w) { + Trie* node = this; + for (char c : w) { + int idx = c - 'a'; + if (node->children[idx] == nullptr || !node->children[idx]->isEnd) { return false; + } + node = node->children[idx]; + } return true; } }; + +class Solution { +public: + string longestWord(vector& words) { + Trie trie; + for (const string& w : words) { + trie.insert(w); + } + + string ans = ""; + for (const string& w : words) { + if (trie.search(w) && (ans.length() < w.length() || (ans.length() == w.length() && w < ans))) { + ans = w; + } + } + return ans; + } +}; ``` #### Go ```go +type Trie struct { + children [26]*Trie + isEnd bool +} + +func (t *Trie) insert(w string) { + node := t + for i := 0; i < len(w); i++ { + idx := w[i] - 'a' + if node.children[idx] == nil { + node.children[idx] = &Trie{} + } + node = node.children[idx] + } + node.isEnd = true +} + +func (t *Trie) search(w string) bool { + node := t + for i := 0; i < len(w); i++ { + idx := w[i] - 'a' + if node.children[idx] == nil || !node.children[idx].isEnd { + return false + } + node = node.children[idx] + } + return true +} + func longestWord(words []string) string { - s := make(map[string]bool) + trie := &Trie{} for _, w := range words { - s[w] = true + trie.insert(w) } - cnt := 0 + ans := "" - check := func(word string) bool { - for i, n := 1, len(word); i < n; i++ { - if !s[word[:i]] { - return false - } - } - return true - } - for w, _ := range s { - n := len(w) - if check(w) { - if cnt < n { - cnt, ans = n, w - } else if cnt == n && w < ans { - ans = w - } + for _, w := range words { + if trie.search(w) && (len(ans) < len(w) || (len(ans) == len(w) && w < ans)) { + ans = w } } return ans @@ -180,50 +263,160 @@ func longestWord(words []string) string { #### TypeScript ```ts -function longestWord(words: string[]): string { - words.sort((a, b) => { - const n = a.length; - const m = b.length; - if (n === m) { - return a < b ? -1 : 1; - } - return m - n; - }); - for (const word of words) { - let isPass = true; - for (let i = 1; i <= word.length; i++) { - if (!words.includes(word.slice(0, i))) { - isPass = false; - break; +class Trie { + children: (Trie | null)[] = new Array(26).fill(null); + isEnd: boolean = false; + + insert(w: string): void { + let node: Trie = this; + for (let i = 0; i < w.length; i++) { + const idx: number = w.charCodeAt(i) - 'a'.charCodeAt(0); + if (node.children[idx] === null) { + node.children[idx] = new Trie(); } + node = node.children[idx]!; } - if (isPass) { - return word; + node.isEnd = true; + } + + search(w: string): boolean { + let node: Trie = this; + for (let i = 0; i < w.length; i++) { + const idx: number = w.charCodeAt(i) - 'a'.charCodeAt(0); + if (node.children[idx] === null || !node.children[idx]!.isEnd) { + return false; + } + node = node.children[idx]!; } + return true; } - return ''; +} + +function longestWord(words: string[]): string { + const trie = new Trie(); + for (const w of words) { + trie.insert(w); + } + + let ans = ''; + for (const w of words) { + if (trie.search(w) && (ans.length < w.length || (ans.length === w.length && w < ans))) { + ans = w; + } + } + return ans; } ``` #### Rust ```rust +struct Trie { + children: [Option>; 26], + is_end: bool, +} + +impl Trie { + fn new() -> Self { + Trie { + children: Default::default(), + is_end: false, + } + } + + fn insert(&mut self, w: &str) { + let mut node = self; + for c in w.chars() { + let idx = (c as usize) - ('a' as usize); + if node.children[idx].is_none() { + node.children[idx] = Some(Box::new(Trie::new())); + } + node = node.children[idx].as_mut().unwrap(); + } + node.is_end = true; + } + + fn search(&self, w: &str) -> bool { + let mut node = self; + for c in w.chars() { + let idx = (c as usize) - ('a' as usize); + if node.children[idx].is_none() || !node.children[idx].as_ref().unwrap().is_end { + return false; + } + node = node.children[idx].as_ref().unwrap(); + } + true + } +} + impl Solution { - pub fn longest_word(mut words: Vec) -> String { - words.sort_unstable_by(|a, b| (b.len(), a).cmp(&(a.len(), b))); - for word in words.iter() { - let mut is_pass = true; - for i in 1..=word.len() { - if !words.contains(&word[..i].to_string()) { - is_pass = false; - break; - } + pub fn longest_word(words: Vec) -> String { + let mut trie = Trie::new(); + for w in &words { + trie.insert(w); + } + + let mut ans = String::new(); + for w in words { + if trie.search(&w) && (ans.len() < w.len() || (ans.len() == w.len() && w < ans)) { + ans = w; } - if is_pass { - return word.clone(); + } + ans + } +} +``` + +#### JavaScript + +```js +/** + * @param {string[]} words + * @return {string} + */ +var longestWord = function (words) { + const trie = new Trie(); + for (const w of words) { + trie.insert(w); + } + + let ans = ''; + for (const w of words) { + if (trie.search(w) && (ans.length < w.length || (ans.length === w.length && w < ans))) { + ans = w; + } + } + return ans; +}; + +class Trie { + constructor() { + this.children = Array(26).fill(null); + this.isEnd = false; + } + + insert(w) { + let node = this; + for (let i = 0; i < w.length; i++) { + const idx = w.charCodeAt(i) - 'a'.charCodeAt(0); + if (node.children[idx] === null) { + node.children[idx] = new Trie(); } + node = node.children[idx]; } - String::new() + node.isEnd = true; + } + + search(w) { + let node = this; + for (let i = 0; i < w.length; i++) { + const idx = w.charCodeAt(i) - 'a'.charCodeAt(0); + if (node.children[idx] === null || !node.children[idx].isEnd) { + return false; + } + node = node.children[idx]; + } + return true; } } ``` diff --git a/solution/0700-0799/0720.Longest Word in Dictionary/Solution.cpp b/solution/0700-0799/0720.Longest Word in Dictionary/Solution.cpp index 49ea37bbdd0b2..8746bd16bc959 100644 --- a/solution/0700-0799/0720.Longest Word in Dictionary/Solution.cpp +++ b/solution/0700-0799/0720.Longest Word in Dictionary/Solution.cpp @@ -1,26 +1,47 @@ -class Solution { +class Trie { public: - string longestWord(vector& words) { - unordered_set s(words.begin(), words.end()); - int cnt = 0; - string ans = ""; - for (auto w : s) { - int n = w.size(); - if (check(w, s)) { - if (cnt < n) { - cnt = n; - ans = w; - } else if (cnt == n && w < ans) - ans = w; + Trie* children[26] = {nullptr}; + bool isEnd = false; + + void insert(const string& w) { + Trie* node = this; + for (char c : w) { + int idx = c - 'a'; + if (node->children[idx] == nullptr) { + node->children[idx] = new Trie(); } + node = node->children[idx]; } - return ans; + node->isEnd = true; } - bool check(string& word, unordered_set& s) { - for (int i = 1, n = word.size(); i < n; ++i) - if (!s.count(word.substr(0, i))) + bool search(const string& w) { + Trie* node = this; + for (char c : w) { + int idx = c - 'a'; + if (node->children[idx] == nullptr || !node->children[idx]->isEnd) { return false; + } + node = node->children[idx]; + } return true; } -}; \ No newline at end of file +}; + +class Solution { +public: + string longestWord(vector& words) { + Trie trie; + for (const string& w : words) { + trie.insert(w); + } + + string ans = ""; + for (const string& w : words) { + if (trie.search(w) && (ans.length() < w.length() || (ans.length() == w.length() && w < ans))) { + ans = w; + } + } + return ans; + } +}; diff --git a/solution/0700-0799/0720.Longest Word in Dictionary/Solution.go b/solution/0700-0799/0720.Longest Word in Dictionary/Solution.go index 3cca4beb6f63b..d6d857180e6fd 100644 --- a/solution/0700-0799/0720.Longest Word in Dictionary/Solution.go +++ b/solution/0700-0799/0720.Longest Word in Dictionary/Solution.go @@ -1,27 +1,43 @@ +type Trie struct { + children [26]*Trie + isEnd bool +} + +func (t *Trie) insert(w string) { + node := t + for i := 0; i < len(w); i++ { + idx := w[i] - 'a' + if node.children[idx] == nil { + node.children[idx] = &Trie{} + } + node = node.children[idx] + } + node.isEnd = true +} + +func (t *Trie) search(w string) bool { + node := t + for i := 0; i < len(w); i++ { + idx := w[i] - 'a' + if node.children[idx] == nil || !node.children[idx].isEnd { + return false + } + node = node.children[idx] + } + return true +} + func longestWord(words []string) string { - s := make(map[string]bool) + trie := &Trie{} for _, w := range words { - s[w] = true + trie.insert(w) } - cnt := 0 + ans := "" - check := func(word string) bool { - for i, n := 1, len(word); i < n; i++ { - if !s[word[:i]] { - return false - } - } - return true - } - for w, _ := range s { - n := len(w) - if check(w) { - if cnt < n { - cnt, ans = n, w - } else if cnt == n && w < ans { - ans = w - } + for _, w := range words { + if trie.search(w) && (len(ans) < len(w) || (len(ans) == len(w) && w < ans)) { + ans = w } } return ans -} \ No newline at end of file +} diff --git a/solution/0700-0799/0720.Longest Word in Dictionary/Solution.java b/solution/0700-0799/0720.Longest Word in Dictionary/Solution.java index 955f075a8dc2f..b0d44ba1e098a 100644 --- a/solution/0700-0799/0720.Longest Word in Dictionary/Solution.java +++ b/solution/0700-0799/0720.Longest Word in Dictionary/Solution.java @@ -1,30 +1,46 @@ -class Solution { - private Set s; +class Trie { + private Trie[] children = new Trie[26]; + private boolean isEnd = false; - public String longestWord(String[] words) { - s = new HashSet<>(Arrays.asList(words)); - int cnt = 0; - String ans = ""; - for (String w : s) { - int n = w.length(); - if (check(w)) { - if (cnt < n) { - cnt = n; - ans = w; - } else if (cnt == n && w.compareTo(ans) < 0) { - ans = w; - } + public void insert(String w) { + Trie node = this; + for (char c : w.toCharArray()) { + int idx = c - 'a'; + if (node.children[idx] == null) { + node.children[idx] = new Trie(); } + node = node.children[idx]; } - return ans; + node.isEnd = true; } - private boolean check(String word) { - for (int i = 1, n = word.length(); i < n; ++i) { - if (!s.contains(word.substring(0, i))) { + public boolean search(String w) { + Trie node = this; + for (char c : w.toCharArray()) { + int idx = c - 'a'; + if (node.children[idx] == null || !node.children[idx].isEnd) { return false; } + node = node.children[idx]; } return true; } -} \ No newline at end of file +} + +class Solution { + public String longestWord(String[] words) { + Trie trie = new Trie(); + for (String w : words) { + trie.insert(w); + } + String ans = ""; + for (String w : words) { + if (trie.search(w) + && (ans.length() < w.length() + || (ans.length() == w.length() && w.compareTo(ans) < 0))) { + ans = w; + } + } + return ans; + } +} diff --git a/solution/0700-0799/0720.Longest Word in Dictionary/Solution.js b/solution/0700-0799/0720.Longest Word in Dictionary/Solution.js new file mode 100644 index 0000000000000..8f54c997eb696 --- /dev/null +++ b/solution/0700-0799/0720.Longest Word in Dictionary/Solution.js @@ -0,0 +1,49 @@ +/** + * @param {string[]} words + * @return {string} + */ +var longestWord = function (words) { + const trie = new Trie(); + for (const w of words) { + trie.insert(w); + } + + let ans = ''; + for (const w of words) { + if (trie.search(w) && (ans.length < w.length || (ans.length === w.length && w < ans))) { + ans = w; + } + } + return ans; +}; + +class Trie { + constructor() { + this.children = Array(26).fill(null); + this.isEnd = false; + } + + insert(w) { + let node = this; + for (let i = 0; i < w.length; i++) { + const idx = w.charCodeAt(i) - 'a'.charCodeAt(0); + if (node.children[idx] === null) { + node.children[idx] = new Trie(); + } + node = node.children[idx]; + } + node.isEnd = true; + } + + search(w) { + let node = this; + for (let i = 0; i < w.length; i++) { + const idx = w.charCodeAt(i) - 'a'.charCodeAt(0); + if (node.children[idx] === null || !node.children[idx].isEnd) { + return false; + } + node = node.children[idx]; + } + return true; + } +} diff --git a/solution/0700-0799/0720.Longest Word in Dictionary/Solution.py b/solution/0700-0799/0720.Longest Word in Dictionary/Solution.py index bb9be70b2cfee..886a6430341b5 100644 --- a/solution/0700-0799/0720.Longest Word in Dictionary/Solution.py +++ b/solution/0700-0799/0720.Longest Word in Dictionary/Solution.py @@ -1,12 +1,38 @@ +class Trie: + def __init__(self): + self.children: List[Optional[Trie]] = [None] * 26 + self.is_end = False + + def insert(self, w: str): + node = self + for c in w: + 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, w: str) -> bool: + node = self + for c in w: + idx = ord(c) - ord("a") + if node.children[idx] is None: + return False + node = node.children[idx] + if not node.is_end: + return False + return True + + class Solution: def longestWord(self, words: List[str]) -> str: - cnt, ans = 0, '' - s = set(words) - for w in s: - n = len(w) - if all(w[:i] in s for i in range(1, n)): - if cnt < n: - cnt, ans = n, w - elif cnt == n and w < ans: - ans = w + trie = Trie() + for w in words: + trie.insert(w) + ans = "" + for w in words: + if trie.search(w) and ( + len(ans) < len(w) or (len(ans) == len(w) and ans > w) + ): + ans = w return ans diff --git a/solution/0700-0799/0720.Longest Word in Dictionary/Solution.rs b/solution/0700-0799/0720.Longest Word in Dictionary/Solution.rs index fc3c4673b768f..24091db61cb1f 100644 --- a/solution/0700-0799/0720.Longest Word in Dictionary/Solution.rs +++ b/solution/0700-0799/0720.Longest Word in Dictionary/Solution.rs @@ -1,18 +1,54 @@ -impl Solution { - pub fn longest_word(mut words: Vec) -> String { - words.sort_unstable_by(|a, b| (b.len(), a).cmp(&(a.len(), b))); - for word in words.iter() { - let mut is_pass = true; - for i in 1..=word.len() { - if !words.contains(&word[..i].to_string()) { - is_pass = false; - break; - } +struct Trie { + children: [Option>; 26], + is_end: bool, +} + +impl Trie { + fn new() -> Self { + Trie { + children: Default::default(), + is_end: false, + } + } + + fn insert(&mut self, w: &str) { + let mut node = self; + for c in w.chars() { + let idx = (c as usize) - ('a' as usize); + if node.children[idx].is_none() { + node.children[idx] = Some(Box::new(Trie::new())); + } + node = node.children[idx].as_mut().unwrap(); + } + node.is_end = true; + } + + fn search(&self, w: &str) -> bool { + let mut node = self; + for c in w.chars() { + let idx = (c as usize) - ('a' as usize); + if node.children[idx].is_none() || !node.children[idx].as_ref().unwrap().is_end { + return false; } - if is_pass { - return word.clone(); + node = node.children[idx].as_ref().unwrap(); + } + true + } +} + +impl Solution { + pub fn longest_word(words: Vec) -> String { + let mut trie = Trie::new(); + for w in &words { + trie.insert(w); + } + + let mut ans = String::new(); + for w in words { + if trie.search(&w) && (ans.len() < w.len() || (ans.len() == w.len() && w < ans)) { + ans = w; } } - String::new() + ans } } diff --git a/solution/0700-0799/0720.Longest Word in Dictionary/Solution.ts b/solution/0700-0799/0720.Longest Word in Dictionary/Solution.ts index 4c73b31ddc97d..6803cc5a46d21 100644 --- a/solution/0700-0799/0720.Longest Word in Dictionary/Solution.ts +++ b/solution/0700-0799/0720.Longest Word in Dictionary/Solution.ts @@ -1,23 +1,43 @@ -function longestWord(words: string[]): string { - words.sort((a, b) => { - const n = a.length; - const m = b.length; - if (n === m) { - return a < b ? -1 : 1; +class Trie { + children: (Trie | null)[] = new Array(26).fill(null); + isEnd: boolean = false; + + insert(w: string): void { + let node: Trie = this; + for (let i = 0; i < w.length; i++) { + const idx: number = w.charCodeAt(i) - 'a'.charCodeAt(0); + if (node.children[idx] === null) { + node.children[idx] = new Trie(); + } + node = node.children[idx]!; } - return m - n; - }); - for (const word of words) { - let isPass = true; - for (let i = 1; i <= word.length; i++) { - if (!words.includes(word.slice(0, i))) { - isPass = false; - break; + node.isEnd = true; + } + + search(w: string): boolean { + let node: Trie = this; + for (let i = 0; i < w.length; i++) { + const idx: number = w.charCodeAt(i) - 'a'.charCodeAt(0); + if (node.children[idx] === null || !node.children[idx]!.isEnd) { + return false; } + node = node.children[idx]!; } - if (isPass) { - return word; + return true; + } +} + +function longestWord(words: string[]): string { + const trie = new Trie(); + for (const w of words) { + trie.insert(w); + } + + let ans = ''; + for (const w of words) { + if (trie.search(w) && (ans.length < w.length || (ans.length === w.length && w < ans))) { + ans = w; } } - return ''; + return ans; }