030-串联所有单词的子串
原题:串联所有单词的子串
思路:滑动窗口
思路
这题其实很容器就能想到用哈希表 + 滑动窗口来解决,但是很多人会被字符串中与子串单词不同长度的单词拦下
其实并不用考虑如何跳过不同长度的单词,我们只要把每一个字符都遍历过就 ok
例如我们有一个字符串 "fofoobarfoo"
,单词列表 ["foo", "bar"]
单词长度为 wordLen = 3
,我们只需要处理从下标 0
到 wordLen - 1
开始遍历的情况即可,下面枚举下遍历过程。
遍历过程
每次遍历下标步数取单词长度 wordLen
即 3
第一次 i = 0
有以下结果组合: "fofoob"
, "oobarf"
第二次 i = 1
: "ofooba"
, "obarfo"
第三次 i = 2
: "foobar"
, "barfoo"
遍历的所有组合中已经包含了所有结果,不需要考虑中间遇到的长度不相等的单词
思路简述
1. 设计一个哈希表来确定当前的子串是合法的
题目要求不能有其它单词、单词出现次数必须一致、任意排序,从而可以很快想到用单词哈希表记录其出现次数即可 const map = { "wordA": 1, "wordB": 2, ... }
2. 接着就是一些基础变量的初始化
单个单词长度 wordLen
子串长度 wordTotalLen
结果 result
3. 遍历字符串
前面说到的,需要遍历几种不同的情况
1 | for (let i = 0; i < wordLen; i++) { |
4. 滑动窗口
以当前下标为起点开始滑动窗口 left = right = i
变量 count
记录单词出现的总次数
变量 tmpMap
记录当前子串的单词出现次数
开始一个循环,不停的移动窗口右侧,每次移动 wordLen
长度直到剩余字符不满足一个单词的长度 right + wordLen <= s.length
在循环体内每次移动完窗口右侧后 right += wordLen
,获得最新拿到的单词
判断单词是否存在,若不存在则清空 tmpMap
和 count
,窗口左侧移动到当前窗口右侧 left = right
若存在则在临时哈希表中记录次数并记录总次数 tmpMap[word]++, count++
记录完后若当前单词出现字数超过合法次数,则移动窗口左侧到当前单词左侧,即舍弃掉前面的结果
最后经过上面去重后,如果当前计数等于单词数,则当前窗口内的为合法结果
完整实现
1 | /** |