Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
一.题目
438. 找到字符串中所有字母异位词 给定两个字符串
s和p,找到s中所有p的异位词的子串,返回这些子串的起始索引。不考虑答案输出的顺序。 异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。 示例 1:
输入: s = "cbaebabacd", p = "abc"
输出: [0,6]
解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。
示例 2:
输入: s = "abab", p = "ab"
输出: [0,1,2]
解释:
起始索引等于 0 的子串是 "ab", 它是 "ab" 的异位词。
起始索引等于 1 的子串是 "ba", 它是 "ab" 的异位词。
起始索引等于 2 的子串是 "ab", 它是 "ab" 的异位词。
提示:
1 <= s.length, p.length <= 3 * 104s和p仅包含小写字母
二、思路分析:
看题目中说的时寻找字符串中的字母异位词,但是实际上还是寻找字符串中跟目标串所有排列中相等的子串问题,对于这种子串问题,还是利用滑动窗口的思想进行求解,求解的思路跟我上一篇文章几乎没有什么差别。
这个题目主要求出目标串的异位词,我们就可以利用这个点对框架进行优化,将window滑动窗口对象转变为Map数据结构更为合适,首先如果移入的字符在目标串当中,那么Map数据结构直接使用clear方法将存储的数组全部清空,如何right-left的长度没有跟目标串的长度相等也不用考虑,相等的话直接进入判断符合的字符数值valid是否与目标串的字符数值相等,相等则直接向结果result推入left数值,在进行滑动窗口操作再继续循环直到右指针到达字符串s的最右端。
三、代码:
/**
* @param {string} s
* @param {string} p
* @return {number[]}
*/
var findAnagrams = function(s, p) {
//分别计算字符串长度
let slen = s.length;
let plen = p.length;
//定义滑动窗口以及符合数
let left = 0,right = 0,valid = 0;
let result = [];
//统计目标字符串的个数
const objectS = new Map();
for(let i=0;i<plen;i++){
objectS.set(p[i],objectS.has(p[i])?objectS.get(p[i])+1:1);
}
//统计滑动窗口的值
const window = new Map();
while(right<slen){
let c = s[right];
right++;
//进入窗口的是所需的字符就加入
if(objectS.has(c)){
window.set(c,window.has(c)?window.get(c)+1:1);
if(window.get(c) == objectS.get(c)) valid++;
}else{
left=right;
valid = 0;
window.clear();
continue;
}
if(right-left == plen){
if(valid == objectS.size){
result.push(left);
}
//进行滑动窗口操作
let x = s[left];
left++;
if(objectS.has(x)){
if(window.get(x) == objectS.get(x)) valid--;
window.set(x,window.get(x)-1);
}
}
}
return result;
};
四、总结:
这是字符串问题的第三题,利用滑动窗口的框架做题思路还是非常清晰的,针对特定的结果只需要优化一部分代码就可以了,如果熟练掌握滑动窗口思想遇到这类问题往往能够举一反三!根据labuladong大佬的思路进行算法的求解果然很得心应手0.0