Offer 驾到,掘友接招!我正在参与 2022 春招打卡活动,点击查看活动详情。
一、题目描述:
- 串联所有单词的子串 —— 难度困难
给定一个字符串 s 和一些 长度相同 的单词 words 。找出 s 中恰好可以由 words 中所有单词串联形成的子串的起始位置。
注意子串要与 words 中的单词完全匹配,中间不能有其他字符 ,但不需要考虑 words 中单词串联的顺序。
示例 1:
输入:s = "barfoothefoobarman", words = ["foo","bar"]
输出:[0,9]
解释:
从索引 0 和 9 开始的子串分别是 "barfoo" 和 "foobar" 。
输出的顺序不重要, [9,0] 也是有效答案。
示例 2:
输入:s = "wordgoodgoodgoodbestword", words = ["word","good","best","word"]
输出:[]
示例 3:
输入:s = "barfoofoobarthefoobarman", words = ["bar","foo","the"]
输出:[6,9,12]
提示:
1 <= s.length <= 10^4
s 由小写英文字母组成
1 <= words.length <= 5000
1 <= words[i].length <= 30
words[i] 由小写英文字母组成
二、题目和思路分析:
这道题比较难, 暴力破解肯定是不行的,因为1 <= s.length <= 10^4
,1 <= words.length <= 5000
,1 <= words[i].length <= 30
,这些限定条件相当于堵死了暴力破解的路。
那么还有什么好方法呢?
除了在words上考虑,还可以在s上面下功夫好好想一下,因为s必定是要进行遍历的。这么想起来,只要遍历s,考虑s[i]——s[i+words.length]是否完全等于words即可,等于则返回i。
值得考虑的是:s[i]——s[i+words.length]是字符串,words是数组,那么如何进行快速对比呢?
如果把words转为对象,比如:
words = ['word', 'word', 'strr', 'intt']
转化为map对象就是:
{
word: 2,
strr: 1,
intt: 1,
}
然后对s[i]——s[i+words.length]也进行转map对象的操作,遍历两个对象是否相等即可。
复制代码
困难的问题这么想,好像也挺简单的,看起来像是暴力破解,但还是比暴力破解优秀很多,并且中间可以判断首子串是否属于words,不属于则跳过。
既然思路看起来没问题,那么代码搞起来!
三、代码:
代码实现如下:
/**
* @param {string} s
* @param {string[]} words
* @return {number[]}
*/
var findSubstring = function(s, words) {
let len = words.length // words元素个数
let wlen = words[0].length // words单个元素长度
let wslen = len*wlen // words全部字符长度
if(s.length < wslen) return [] // 如果s长度小于words所有单词拼接的字符串长度,直接返回[]
let arr = []
let wordsObj = new Map()
for (let word of words) {
let count = wordsObj.has(word) ? wordsObj.get(word) : 0
wordsObj.set(word, count + 1)
}
for(let i = 0; i < s.length; i++){
if(i + wslen > s.length) break
if(words.includes(s.substr(i, wlen))){
if (objEqual(s.substr(i, wslen))) {
arr.push(i)
}
}else{
continue
}
}
return arr
// 对比当前字符串转map对象后和wordObj是否一致
function objEqual(str){
let bool = true
let map = new Map()
for (let i = 0; i < len; i++) {
let word = str.substring(i * wlen, (i + 1) * wlen)
let count = map.has(word) ? map.get(word) : 0
map.set(word, count + 1)
}
for (let [key, value] of wordsObj) {
if (!map.has(key) || map.get(key) !== value) {
bool = false
}
}
console.log(bool)
return bool
}
};
复制代码
四、总结:
这次的困难题好像没那么难,但是优化我倒是写了好久,才优化了100ms,总之大部分的题目使用遍历都是能够解决的,我们要进一步考虑的话,就是想想如何把遍历写的更加优雅。
加油吧!