intcmp(constvoid * a, constvoid * b) { char * pa = *(char **)a; char * pb = *(char **)b; int la = strlen(pa); int lb = strlen(pb); if (la != lb) { return la - lb; } else { returnstrcmp(pb, pa); } }
var longestWord = function(words) { words.sort((a, b) => { if (a.length !== b.length) { return a.length - b.length; } else { return b.localeCompare(a); } }) let longest = ""; let candidates = newSet(); candidates.add(""); const n = words.length; for (let i = 0; i < n; i++) { const word = words[i]; if (candidates.has(word.slice(0, word.length - 1))) { candidates.add(word); longest = word; } } return longest; };
[sol1-Golang]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
funclongestWord(words []string) (longest string) { sort.Slice(words, func(i, j int)bool { s, t := words[i], words[j] returnlen(s) < len(t) || len(s) == len(t) && s > t })
candidates := map[string]struct{}{"": {}} for _, word := range words { if _, ok := candidates[word[:len(word)-1]]; ok { longest = word candidates[word] = struct{}{} } } return longest }
复杂度分析
时间复杂度:O(\sum_{0 \le i < n} l_i \times \log n),其中 n 是数组 words 的长度,l_i 是单词 words}[i] 的长度。对数组 words 排序最多需要 O(\sum_{0 \le i < n} l_i \times \log n) 的时间,排序后遍历数组 words 将单词加入哈希集合并得到答案最多需要 O(\sum_{0 \le i < n} l_i) 的时间。由于在渐进意义下 O(\sum_{0 \le i < n} l_i) 小于 O(\sum_{0 \le i < n} l_i \times \log n),因此时间复杂度是 O(\sum_{0 \le i < n} l_i \times \log n)。
空间复杂度:O(\sum_{0 \le i < n} l_i),其中 n 是数组 words 的长度,l_i 是单词 words}[i] 的长度。排序需要 O(\log n) 的空间,哈希集合需要 O(\sum_{0 \le i < n} l_i) 的空间,由于在渐进意义下 O(\log n) 小于 O(\sum_{0 \le i < n} l_i),因此空间复杂度是 O(\sum_{0 \le i < n} l_i)。
创建字典树,遍历数组 words 并将每个单词插入字典树。当所有的单词都插入字典树之后,将答案初始化为空字符串,再次遍历数组 words,判断每个单词是否是符合要求的单词,并更新答案。如果一个单词是符合要求的单词,则比较当前单词与答案,如果当前单词的长度大于答案的长度,或者当前单词的长度等于答案的长度且当前单词的字典序小于答案的字典序,则将答案更新为当前单词。
defsearch(self, word: str) -> bool: node = self for ch in word: ch = ord(ch) - ord('a') if node.children[ch] isNoneornot node.children[ch].isEnd: returnFalse node = node.children[ch] returnTrue
classSolution: deflongestWord(self, words: List[str]) -> str: t = Trie() for word in words: t.insert(word) longest = "" for word in words: if t.search(word) and (len(word) > len(longest) orlen(word) == len(longest) and word < longest): longest = word return longest
type Trie struct { children [26]*Trie isEnd bool }
func(t *Trie) Insert(word string) { node := t for _, ch := range word { ch -= 'a' if node.children[ch] == nil { node.children[ch] = &Trie{} } node = node.children[ch] } node.isEnd = true }
func(t *Trie) Search(word string) bool { node := t for _, ch := range word { ch -= 'a' if node.children[ch] == nil || !node.children[ch].isEnd { returnfalse } node = node.children[ch] } returntrue }
funclongestWord(words []string) (longest string) { t := &Trie{} for _, word := range words { t.Insert(word) } for _, word := range words { if t.Search(word) && (len(word) > len(longest) || len(word) == len(longest) && word < longest) { longest = word } } return longest }
insert(word) { let node = this; for (let i = 0; i < word.length; i++) { const ch = word[i]; const index = ch.charCodeAt() - 'a'.charCodeAt(); if (!node.children[index]) { node.children[index] = newNode(); } node = node.children[index]; } node.isEnd = true; }
search(word) { let node = this; for (let i = 0; i < word.length; i++) { const ch = word[i]; const index = ch.charCodeAt() - 'a'.charCodeAt(); if (!node.children[index] || !node.children[index].isEnd) { returnfalse; } node = node.children[index]; } return node && node.isEnd; } }
复杂度分析
时间复杂度:O(\sum_{0 \le i < n} l_i),其中 n 是数组 words 的长度,l_i 是单词 words}[i] 的长度。将数组 words 中的每个单词加入字典树需要 O(\sum_{0 \le i < n} l_i) 的时间,在字典树中判断每个单词是否符合要求并得到答案也需要 O(\sum_{0 \le i < n} l_i) 的时间。
空间复杂度:O(\sum_{0 \le i < n} l_i),其中 n 是数组 words 的长度,l_i 是单词 words}[i] 的长度。字典树最多需要 O(\sum_{0 \le i < n} l_i) 的空间。