Leetcode-JS解法-滑动窗口

什么是滑动窗口

滑动窗口的思想是:维护一个窗口,通过滑动窗口的方式在数组或字符串上移动。窗口通常由两个指针(左指针和右指针)定义,左指针指向窗口的起始位置,右指针指向窗口的结束位置。

  • 初始化左右指针left和right,左右指针之间的内容就是窗口
  • 定义一个变量result记录当前的滑动窗口的结果
  • 定义一个变量bestResult记录当前滑动窗口下的最优结果

窗口的左边界和右边界永远只能向右移动,而不能向左移动,这是为了保证滑动窗口的时间复杂度是 O(n)。如果左右边界向左移动的话,这叫做"回溯",算法的时间复杂度就可能不止 O(n)

其实双指针和滑动窗口是有些许区别的。滑动窗口一句话就是右指针先出发,左指针视情况追赶右指针

模板代码

寻找最长滑窗

scss 复制代码
初始化left,right,result,bestResult
while(右指针没有到结尾){
  窗口扩大,加入right对应元素,更新当前result
	while(result不满足要求){
     窗口缩小,移除left对应元素,left右移
  }
	更新最优结果bestResult(注意是在外面更新)
  right++
}
返回bestResult

寻找最短滑窗

scss 复制代码
初始化left,right,result,bestResult
while(右指针没有到结尾){
  窗口扩大,加入right对应元素,更新当前result
	while(result不满足要求){
    更新最优结果bestResult(在while内更新)
    窗口缩小,移除left对应元素,left右移
  }
  right++
}
返回bestResult

相关题目

简-和为s的连续正数序列-剑指o57

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

思路:

滑动窗口只有 右边界向右移动(扩大窗口) 和 左边界向右移动(缩小窗口)

  • 当窗口的和<target的时候,窗口的和需要增加,右边界向右移动
  • 当窗口的和>target的时候,窗口的和需要减少,左边界向右移动
  • 当窗口的和=target的时候,记录当前结果[i,j),接下来找i+1开头的序列,窗口的左边界向右移动
javascript 复制代码
/**
 * @param {number} target
 * @return {number[][]}
 */
var findContinuousSequence = function(target) {
    // 这个窗口是一个左闭右开的区间
    let i=1//左边界
    let j=1//右边界
    let sum=0 //滑动窗口的数字和
    const res=[]
    // 只循环到目标值的一半,超过一半的话,加起来会超过target
    while(i<=Math.floor(target/2)){
        // 右边界移动
        if(sum<target){
            sum+=j
            j++
        }
        // 左边界移动
        else if(sum>target){
            sum-=i
            i++
        }
        // 记录结果
        else{
            let arr=[]
            for(let k=i;k<j;k++){
                arr.push(k)
            }
            res.push(arr)
            // 左边界移动
            sum-=i
            i++
        }
    }
    return res
};

中-长度最小的子数组-209

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

思路:本质上是找最小滑窗

  • 定义左右指针,指向滑动窗口的开始和结束位置
  • 从右移动右指针,计算窗口内数之和sum
  • 如果sum>=target,就更新子数组最小长度(right-left+1)
  • 向右移动left,同时sum-left的值,直到sum<target
scss 复制代码
var minSubArrayLen = function (target, nums) {
   let left = right = sum = bestResult = 0;
  //右指针到最右边结束循环
    while(right<nums.lenght){
      sum=sum+nums[right]//记录当前滑动窗口的值
      // 这里记住是要用while,而不是if!!
      // 满足条件
      while(sum>=target){
         // 如果当前的最好的结果大于左右指针之间的长度,更新最优结果
        if(right-left+1<bestResult||bestResult==0){
           bestResult = right - left + 1;
        }
        // 将左指针向右移,并且左指针的值从当前结果里面减掉
        sum -= nums[left];
        left++;
      }
      right++; // 向右滑动窗口
    }
    return bestResult;
}

中-无重复字符的最长字符串-3

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

思路:本质是找最长滑窗

  • 创建一个set
  • 两个指针(left和right)
  • 如果set里面没有sright,说明目前为止还没有重复的字符,把sright添加到set里,然后更新最大不重复字符的数量
  • 如果set里有sright,则从set里开始删除sleft,并且递增,再检查set是否有sright,循环直到没有sright为止
  • 重复步骤3,4,直到遍历完整个字符串

使用set

scss 复制代码
/**
 * @param {string} s
 * @return {number}
 */
var lengthOfLongestSubstring = function(s) {
     if(s.length === 0){
        return 0
    }
    const set = new Set()
    let left=0,right=0,maxLength=0
    while(right<s.length){
        if(!set.has(s[right])){
            set.add(s[right])
          	right++
            // 更新最大长度
            maxLength=Math.max(maxLength,set.size)
        }else{
            // 存在重复值,则删除set中s[i]以及之前的元素
            while(set.has(s[right])){
                set.delete(s[left])
                left++
            }
            set.add(s[right])
          	right++
        }
    }
    return maxLength
};

不使用set

这种写法更容易理解,但是需要考虑重复的情况

scss 复制代码
/**
 * @param {string} s
 * @return {number}
 */
var lengthOfLongestSubstring = function(s) {
    let left=right=len=maxLen=0
    let arr=[]//记录当前滑动窗口包含的字符
    //当右指针指向字符串最右边时停止循环
    while(right<s.length){
        //如果窗口中的字符串包含了右指针指向的元素
        if(arr.includes(s[right])){
            // 当arr中包含右指针指向的字符,删除该元素
            while(arr.includes(s[right])){
                arr.shift()//删除
                len--//更新当前的长度
                left++//左指针右移动
            }
            //循环结束后,arr中不包含右指针指向的元素
            arr.push(s[right])
            len++
            right++
        }else{
            arr.push(s[right])
            len++
            //如果当前长度大于最大长度
            if(len>maxLen){
                maxLen=len
            }
            right++
        }
    }
    return maxLen
};

中-水果成篮-904

力扣

题目简述:有两个篮子,每个篮子只能放一种水果,找出储存最多水果的方案,本质是找最大滑窗

思路:

Leetcode刷题 904. 水果成篮Fruit Into Baskets_哔哩哔哩_bilibili

  • 定义两个变量,right为窗口的右边界,left为窗口的左边界
  • 使用map储存每个水果最后出现的位置
  • 窗口中只能放两个水果,当出现第三种水果时,将第一种水果去除出去,即移动j的坐标
scss 复制代码
/**
 * @param {number[]} fruits
 * @return {number}
 */
var totalFruit = function(fruits) {
  const map = new Map()
  let max = 1
  let left=0
  for(let right=0;right<tree.length;right++){
    // map用来存储每个水果出现的最后位置
    map.set((tree[i],i))
    // 不满足条件(超过两种水果)
    if(map.size>2){
      // 初始值(给一个最大的值)
      let minIndex = tree.length-1
      // 找到map中比较小的坐标
      for(const [fruit,index] of map){
        if(index<minIndex){
          minIndex = index
        }
      }
      // 删除小坐标的水果
      map.delete(tree[minIndex])
      // j往后移动
      left=minIndex+1
    }
    // 更新最大值
    max = Math.max(max,right-left+1)
  } 
  return max 
};
相关推荐
牧羊人.3333 分钟前
动手学深度学习 07|Resnet网络与迁移学习
网络·人工智能·深度学习·神经网络·算法·cnn·迁移学习
Fly25 分钟前
我来提需求,你带着 Codex 做项目:AI 全栈课程开始实战了
前端
集智飞行44 分钟前
解决mavros2 ros2版本cpu占用高的问题
java·服务器·前端
All for pursuit.1 小时前
【并查集-2】399.除法求值
数据结构·c++·算法·leetcode
迪丽热爱1 小时前
一、C语言概述与程序结构
c语言·开发语言·算法
码爸1 小时前
动态规划介绍
算法·动态规划
w2sfot2 小时前
【JS加密在线】jsjiami.online(让JavaScript 更安全!)
开发语言·javascript·安全
HSunR2 小时前
ruoyi 若依 自定义注解 参数校验
java·前端·数据库
怪奇云呼军2 小时前
教育试听预约后没到课,闪电智能 Voice Agent 如何做分层回访?
人工智能·python·算法·云计算·音视频
Nil2082 小时前
leetcode 416分割等和子集
算法·leetcode·职场和发展