“Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情。”
一、题目描述:
720. 词典中最长的单词
给出一个字符串数组 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] 都只包含小写字母。
二、思路分析:
- 暴力模拟
所求的答案要求为
- 所给的words 中有组成该结果字符串ans的从1~n长度的的字符串,例如单词"world"数组words中有"w", "wo", "wor", 和 "worl"。
- ans长度最长
- ans的字典序即a~z排序最小
因此我们可以暴力模拟,遍历words数组words[i],使用while循环判断数组中是否有words.includes(words[i].slice(0,length-1)),若条件满足,判断长度是否大于之前确定的最长的答案,若长度等于判断字典序的大小
/**
* @param {string[]} words
* @return {string}
*/
var longestWord = function(words) {
let maxl=0,index=-1,n=words.length;
if(n===0)return ''
for(let i=0;i<n;i++){
let len=words[i].length
if(len>=maxl){
let tmp=len-1
while(tmp>=1&&words.includes(words[i].slice(0,tmp))){
tmp--;
}
if(tmp===0){
if(index===-1||len>maxl||words[i]<words[index]){
index=i
maxl=len
}
}
}else continue;
}
return index===-1?'':words[index]
};
- 优化 排序+集合 我们发现上面的方法对于每一个 "wo", "wor", 和 "worl"都要判断"w","wo", "wor"等等,占用许多无用空间,我们用set集合来存储满足条件的字符串,这样判断新的字符串我们只需要判断words[i].slice(0,length-1)是否在集合里面,不需要循环。
而为了只需要判断words[i].slice(0,length-1),我们得保证set中加入的数顺序为长度顺序,即不能先worl再wor。因此我们需要对他们进行按长度进行升序排序
我们希望第一个大于最大长度的字符串的字典序最小,因此当长度相同时按字典序升序排列,这样第一个满足条件的就是同等长度下字典序最小的,更新最大长度和答案。同时我们也要将满足所给的words 中有组成该结果字符串ans的从1~n长度的的字符串,加入集合set中进行后续长度增加后的判断
/**
* @param {string[]} words
* @return {string}
*/
var longestWord = function(words) {
let maxl=0,ans='',n=words.length;
if(n===0)return ''
words.sort((a,b)=>{
if(a.length!==b.length)return a.length-b.length
return a.localeCompare(b)
})
let set=new Set()
set.add('')
for(let i of words){
if(set.has(i.slice(0,i.length-1))){
set.add(i)
if(i.length>maxl){
maxl=i.length
ans=i
}
}
}
return ans
};