携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第26天,点击查看活动详情
题目描述
给出一个字符串数组 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"
提示:
- 1 <= words.length <= 1000
- 1 <= words[i].length <= 30
- 所有输入的字符串 words[i] 都只包含小写字母。
解题思路——Set遍历
题目中要求我们返回的最长单词必须是其他单词逐步拼成的单词。也就是说返回的这个长度为 n 的单词 word 必须有在词典中有其对应的 word.substring(0, 1)、word.substring(0,2)....word.substring(0, n -1 ),这个单词才能算数。
具体步骤如下:
- 初始化一个
Set。 - 遍历
words, 将所有的单词都存入Set集合中。 - 初始化变量
maxWord='',用来记录最长的单词。 - 遍历
words数组,对word的每个单词进行子串的截取,对于每个子串,去Set中查找有没有对应的数据,如果没找到则说明word不算数,没有必要继续遍历word了;如果有则继续查找下一个长度的子串,直到结束,说明该word是满足要求的,同maxWord比较,满足条件则maxWord = word。 - 返回
maxWord。
这里可以对第二次 words 的遍历进行优化,比如说当我们的 maxWord = 'xxxxx',那么我的 maxWord 都这么长了,如果 maxWord 短的单词肯定就直接 pass 了。
题解
var longestWord = function(words) {
const wordSet = new Set();
for(const w of words) {
wordSet.add(w);
}
let maxWord = '';
for(const w of words) {
const lens = w.length;
if(maxWord.length > lens) continue; // 长度小于maxWord的就不用遍历了,减少范围
let flag = false;
for(let i=1; i<lens; ++i) {
if(!wordSet.has(w.substring(0, i))) {
flag = true;
break;
}
}
if(flag) continue;
if(lens > maxWord.length) {
maxWord = w;
} else if(lens === maxWord.length) {
if(w < maxWord) {
maxWord = w;
}
}
}
return maxWord;
};
优化
- 对 words 数组以 length 属性进行排序。
- 初始化一个 wordSet=new Set('')。
- 遍历 words,对于每个单词来说,如果 wordSet 中存在 word.slice(0, -1),也就是存在除了最后一个字符外的字符串的话,就可以把 word 添加进 wordSet,同时同 maxWord 进行比较。
["yo","ew","fc","zrc","yodn","fcm","qm","qmo","fcmz","z","ewq","yod","ewqz","y"] 这个数组来说,遍历到 ew 时,由于 wordSet 中不存在 e,就不能添加到 wordSet 集合中,那么连带的,ewq 和 ewqz 的 slice(0, -1) 全部不存在。如此一来因为 words 按照 length 属性排序,我们只需要判断 slice(0, -1) 就可以了,极大的提高了效率。
var longestWord = function(words) {
words.sort((a,b)=>a.length-b.length);
let maxWord = '';
const wordSet = new Set(['']);
for(const w of words) {
if(wordSet.has(w.slice(0, -1))) {
wordSet.add(w);
if(w.length > maxWord.length) {
maxWord = w;
} else if(w.length === maxWord.length && w < maxWord) {
maxWord = w;
}
}
}
return maxWord;
};
解题思路——Trie树
老观众都知道 Trie 树了,看到什么 “词典” “单词” 啊这种东西,都应该联系到 Trie 树,毕竟人家也叫单词搜索树是吧。
题解
class Trie {
constructor() {
this.children = Object.create(null);
}
insert(word) {
let children = this.children;
for(const w of word) {
if(children[w] === void 0) {
children[w] = new Trie();
}
children = children[w].children;
}
children['#'] = true;
}
}
var longestWord = function(words) {
const root = new Trie();
for(const w of words) {
root.insert(w);
}
let maxCnt = -Infinity, maxWord = '';
for(const w of words) {
const t = searchLongerstWord(w, root);
if(t.length > maxCnt) {
maxCnt = t.length;
maxWord = t;
} else if(t.length === maxCnt && t < maxWord) {
maxCnt = t.length;
maxWord = t;
}
}
return maxWord;
};
const searchLongerstWord = (word, trie) => {
let children = trie.children, s='';
for(const w of word) {
children = children[w].children;
if (children['#']) {
s += w;
} else {
return s;
}
}
return s;
}