【算法】滑动窗口

参考链接

无重复字符的最长子串

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

示例

输入: s = "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
     请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

解法: 滑动窗口str中是没有重复的连续子串,当遍历字符串s时,当发现s[i]在滑动窗口str中出现了,则 将窗口右移一位并添加上当前字符s[i]

/**
 * @param {string} s
 * @return {number}
 */
var lengthOfLongestSubstring = function(s) {
    // if(s.length === 1){
    //     return 1;
    // }
    let subStr = '';
    let maxV = 0;
    for(let i=0;i<s.length;i++){
        let idx = subStr.indexOf(s[i]);
        if(idx===-1){
            subStr += s[i];
        }else{
            subStr = subStr.slice(idx+1)+s[i];
        }
        if(maxV<subStr.length){
                maxV = subStr.length;
        }
    }
    return maxV;
};

串联所有单词的子串

最小覆盖子串

题目: 给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。
示例:

输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"
输入: s = "a", t = "aa"
输出: ""
解释: t 中两个字符 'a' 均应包含在 s 的子串中,
因此没有符合条件的子字符串,返回空字符串。

题解: 利用滑动窗口在s中从头开始滑动,当窗口中的字符包含所有t中字符时,考虑缩小窗口,否则增大窗口
这里利用一个map数据结构来判断当前窗口是否包含所有t中字符,如果向右增大窗口时,当前字符s[right]在map中,则map对应位置减1,代表该字符在窗口出现了。而缩小窗口时,如果s[left]在map中,将map对应位置加1,表示该字符从窗口中移除了。
leetcode链接

/**
 * @param {string} s
 * @param {string} t
 * @return {string}
 */
var minWindow = function(s, t) {
    // 记录当前窗口是否已经包含t中所有字符
    let map = new Map();
    for(let i=0;i<t.length;i++){
        if(map.has(t[i])){
            let tmp = map.get(t[i])
            map.set(t[i], tmp+1);
        }else{
            map.set(t[i], 1);
        }
    }
    let left=0, right=0;
    let startIdx = 0, maxLen = Number.MAX_SAFE_INTEGER;
    while(right<s.length){
        if(map.has(s[right])){
            map.set(s[right], map.get(s[right])-1);
        }
        right++;
        while(check(map)){//当前窗口包含了t,考虑缩小窗口
            if(maxLen>right-left){
                maxLen = right - left;
                startIdx = left;
            }
            if(map.has(s[left])){
                map.set(s[left], map.get(s[left])+1);
            }
            left++;
        }
    }
    if(maxLen==Number.MAX_SAFE_INTEGER){
        return "";
    }
    return s.slice(startIdx, startIdx+maxLen);
};

// 检查当前窗口是否已经包含了所有t中所有字符
function check(map){
    for(let v of map.values()){
        if(v>0){
            return false;
        }
    }
    return true;
}

字符串的排列

题目: 给你两个字符串 s1 和 s2 ,写一个函数来判断 s2 是否包含 s1 的排列。如果是,返回 true ;否则,返回 false 。换句话说,s1 的排列之一是 s2 的 子串 。

示例:

输入:s1 = "ab" s2 = "eidbaooo"
输出:true
解释:s2 包含 s1 的排列之一 ("ba").

输入:s1= "ab" s2 = "eidboaoo"
输出:false

题解: 和上一题思路一样,只是这里需要判断滑动窗口的大小刚好等于s1的长度

/**
 * @param {string} s1
 * @param {string} s2
 * @return {boolean}
 */
var checkInclusion = function(s1, s2) {
    let map = new Map();
    for(let i=0;i<s1.length;i++){
        if(map.has(s1[i])){
            map.set(s1[i],map.get(s1[i])+1);
        }else{
            map.set(s1[i], 1);
        }
    }
    let left=0, right=0;
    while(right<s2.length){
        if(map.has(s2[right])){
            map.set(s2[right], map.get(s2[right])-1);
        }
        right++;
        while(check(map)){
            if((right-left)==s1.length){
                return true;
            }
            if(map.has(s2[left])){
                map.set(s2[left], map.get(s2[left])+1);
            }
            left++;
        }
    }
    return false;
};

function check(map){
    for(v of map.values()){
        if(v>0){
            return false;
        }
    }
    return true;
}

长度最小的子数组

题目: 给定一个含有 n 个正整数的数组和一个正整数 target 。找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
示例:

输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。

题解: 利用滑动窗口

/**
 * @param {number} target
 * @param {number[]} nums
 * @return {number}
 */
var minSubArrayLen = function(target, nums) {
    let left=0, right=0;
    let sum=0;
    let len = Number.MAX_SAFE_INTEGER;
    while(right<nums.length){
        sum += nums[right];
        right++;
        while(sum>=target){
            len = Math.min(len, right-left);
            sum -= nums[left];
            left++;
        }
        
    }
    return len==Number.MAX_SAFE_INTEGER ? 0 : len;
};
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值