leetCode-热题100-子串合集(JavaScript)

子串

[1- 和为K的子数组](#1- 和为K的子数组)

[2- 滑动窗口最大值](#2- 滑动窗口最大值)

[3- 最小覆盖子串](#3- 最小覆盖子串)

1- 和为K的子数组

给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k**的子数组的个数

子数组是数组中元素的连续非空序列。

复制代码
var subarraySum = function(nums, k) {
    // "连续子数组" + "求和"-》前缀和 两个前缀和的差必然是一段连续的区间
    // 哈希表+哈希表
    // 子数组和 = 当前前缀和 - 之前某个时刻的前缀和
    let count = 0
    let currentSum = 0
    let map = new Map()
    // 初始化哈希表,处理从数组下标0开始就满足条件的数组
    map.set(0,1)
    // 
    for(let num of nums){
        currentSum += num // 计算当前前缀和
        // 如果 (当前和 - 目标值) 在之前出现过
        if(map.has(currentSum-k)){
            count += map.get(currentSum-k)
        }
        // 更新 Map:记录当前前缀和出现的次数
        map.set(currentSum,(map.get(currentSum)||0)+1)
    }
    return count
};

2- 滑动窗口最大值

给你一个整数数组 nums,有一个大小为 k的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回 滑动窗口中的最大值

复制代码
var maxSlidingWindow = function(nums, k) {
    // 单调递减队列:保持单调性;队首即最大;移除过期元素
    // 使用数组模拟双端队列
    // queue存储索引值,且索引值对应的数组元素值单调递减
    let queue = []
    let result = []

    // 遍历数组的每个元素
    for(let i = 0; i< nums.length; i++){
        // 1. 维护队列的单调递减性
        // 将队列中所有比当前元素值小的元素对应的索引值出栈
        while(queue.length > 0 && nums[queue[queue.length-1]] <= nums[i]){
            queue.pop()
        }
        // 2. 当前元素的索引值入队
        // 此时队列中剩下的索引值对应的元素值都比当前元素值大 或者是 空队列
        queue.push(i)

        // 3. 移除窗口外的过期索引
        // 窗口的范围是【i-k+1, i】
        if(queue[0] <= i - k){
            queue.shift()
        }

        // 4. 记录当前窗口的最大值
        if(i >= k-1){
            result.push(nums[queue[0]])
        }
    }
    return result
};

3- 最小覆盖子串

给定两个字符串 st,长度分别是 mn,返回 s 中的 最短窗口 子串 ,使得该子串包含 t 中的每一个字符(包括重复字符 )。如果没有这样的子串,返回空字符串""

测试用例保证答案唯一。

复制代码
var minWindow = function(s, t) {
    // 滑动窗口+双指针+Object(用时久)
    // 初始化:need记录t字符串的字符需求;window记录s字符串的窗口字符
    let need = {}
    let window = {}
    // 记录t中的字符需求
    for(let char of t){
        need[char] = (need[char] || 0) + 1
    }

    // 左右双指针模拟滑动窗口,窗口范围[left,right)
    let left = 0
    let right = 0
    // 窗口中满足need数量要求的字符串种类数
    let valid = 0
    // 记录最小子串的起始位置和长度
    let len = Infinity
    let start = 0

    //移动右指针扩大窗口
    while(right < s.length){
        // c:当前移入窗口的字符
        let c = s[right]
        // 右指针右移扩大窗口
        right++
        // 更新窗口内的数据(仅处理t中存在的字符)
        if(need[c]){
            // 窗口中该字符数量加1
            window[c] = (window[c] || 0) + 1
            // 窗口中该字符数量=need中所需数量,该种字符达到要求,valid+1
            if(window[c] === need[c]){
                valid++
            }
        }

        // 当前窗口满足条件(包含t中的每一个字符)
        // 收缩左指针
        while(valid === Object.keys(need).length){
            // 更新最小覆盖的字串
            if(right - left < len){
                // 更新起始位置
                start = left
                // 更新窗口长度,左闭右开直接-
                len = right - left
            }
            // d:当前移除窗口的字符
            let d = s[left]
            // 左指针右移,收缩窗口
            left++
            // 移除的字符是need中需要的
            if(need[d]){
                // 如果之前该字符满足条件,现在移除,不满足条件,valid-1
                if(window[d] === need[d]){
                    valid--
                }
                // 窗口中该字符数量-1
                window[d]--
            }
        }
    }
    // 返回
    return len === Infinity ? '' : s.substr(start,len)
};

var minWindow = function(s, t) {
    // 用ASCII数组,记录t的字符需求
    // 索引对应字符ASCII码,值对应需求数量
    // fill(0),防止后续++的时候出现undefined+1=nan的错误
    let need = Array(128).fill(0)
    // 未凑齐的字符种类数(初始是t的字符种类数)
    let requiredKinds = 0

    for(let char of t){
        const code = char.charCodeAt(0) // 转成ASCII码(比如'A'→65,'B'→66)
        if(need[code] === 0){
            // 首次统计该字符,种类数+1 
            requiredKinds++
        }
        // 该字符的需求数量+1
        need[code]++
    }

    let left = 0
    // 初始化子串的起始索引值和长度
    let start = 0
    let len = Infinity
    // 寻找子串
    for(let right = 0;right < s.length; right++){
        // 窗口区间【left,right】
        // 窗口中新加入的字符对应的ASCII码
        const rChar = s.charCodeAt(right)
        // 对应t的需求数量-1
        need[rChar]--
        // t中该字符的需求数量=0,该窗口中已包含该字符的需求
        if(need[rChar] === 0){
            // 未凑齐的字符种类数-1
            requiredKinds--
        }
        // 未凑齐的字符种类数=0,窗口已包含t中所有字符
        while(requiredKinds === 0){
            // 更新最小子串的长度和起始索引值
            if(right - left < len){
                start = left
                len = right - left
            }
            // 收缩窗口,Lchar:移出窗口的字符对应的ASCII码
            const Lchar = s.charCodeAt(left)
            // 如果窗口之前完全包含该字符
            if(need[Lchar] === 0){
                // 现在移除该字符,窗口未凑齐的字符种类数+1
                requiredKinds++
            }
            // 左指针右移,收缩
            left++
            // need需求中对应+1
            need[Lchar]++
        }
    }
    // str.substr(startIndex, length),第二个参数是长度
    // 窗口区间是[],len需要+1
    return len === Infinity ? '' : s.substr(start,len+1)
};
相关推荐
前端小超超1 小时前
ionic + vue3 + capacitor遇到backButton问题
前端·javascript·vue.js
尋有緣1 小时前
力扣1355-活动参与者
大数据·数据库·leetcode·oracle·数据库开发
姓蔡小朋友1 小时前
算法-滑动窗口
算法
君义_noip2 小时前
信息学奥赛一本通 2134:【25CSPS提高组】道路修复 | 洛谷 P14362 [CSP-S 2025] 道路修复
c++·算法·图论·信息学奥赛·csp-s
EndingCoder2 小时前
枚举类型:常量集合的优雅管理
前端·javascript·typescript
kaikaile19952 小时前
基于拥挤距离的多目标粒子群优化算法(MO-PSO-CD)详解
数据结构·算法
不忘不弃2 小时前
求两组数的平均值
数据结构·算法
leaves falling2 小时前
迭代实现 斐波那契数列
数据结构·算法
珂朵莉MM2 小时前
全球校园人工智能算法精英大赛-产业命题赛-算法巅峰赛 2025年度画像
java·人工智能·算法·机器人
cute_ming2 小时前
关于基于nodeMap重构DOM的最佳实践
java·javascript·重构