LeetCode-刷题记录-滑动窗口合集(本篇blog会持续更新哦~)

一、滑动窗口概述

滑动窗口(Sliding Window)是一种用于解决数组(或字符串)中子数组(或子串)问题的有效算法。

在这里插入图片描述

Sliding Window核心思想:

滑动窗口技术的基本思想是维护一个窗口(一般是一个子数组或子串),该窗口在数组上滑动,并在滑动过程中更新窗口的内容。

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

通过滑动窗口,可以在 ( O(n) ) 的时间复杂度内解决很多子数组(子串)问题,其中 ( n ) 是数组(字符串)的长度。

基本步骤:

  1. 初始化窗口: 定义一个窗口的起始位置和结束位置,通常是两个指针 leftright
  2. 滑动窗口: 不断地增加 right 指针来扩大窗口,直到窗口满足某个条件为止。

在这里插入图片描述

  1. 更新窗口: 一旦满足条件,尝试缩小窗口大小,即增加 left 指针,直到条件不满足为止。
  2. 记录结果: 在滑动窗口的过程中,根据题目要求来记录最终的结果。

二、习题合集

1.LeetCode 209 长度最小的子数组

在这里插入图片描述

  • 滑动窗口O(N)解法:
class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int n = nums.length;  // 数组的长度
        int ans = Integer.MAX_VALUE;  // 初始化结果为最大值,用于存储最短子数组的长度
        int l = 0;  // 左指针,指向滑动窗口的起始位置
        int sum = 0;  // 记录滑动窗口内元素的和
        
        for (int r = 0; r < n; r++) {  // 右指针,扩展滑动窗口
            sum += nums[r];  // 将右指针指向的元素加入窗口
            
            while (sum >= target) {  // 当窗口内元素和大于等于目标值时,尝试缩小窗口
                ans = Math.min(ans, r - l + 1);  // 更新最短子数组的长度
                sum -= nums[l];  // 缩小窗口,左指针向右移动,减少窗口内的元素和
                l++;  // 左指针右移
            }
        }
        
        return ans == Integer.MAX_VALUE ? 0 : ans;  // 如果找不到满足条件的子数组,返回0;否则返回最短子数组的长度
    }
}


2.LeetCode 3 无重复字符的最长子串

在这里插入图片描述


  • 第一版滑动窗口
class Solution {
    public int lengthOfLongestSubstring(String s) {
        Map<Character, Integer> map = new HashMap<>(); // 创建一个哈希表,用来记录字符及其出现的最后位置
        int n = s.length(); // 字符串的长度
        int l = 0, ans = 0; // l表示当前不重复子串的起始位置,ans用来记录最长不重复子串的长度
        
        for (int r = 0; r < n; r++) {
            char c = s.charAt(r); // 获取当前字符
            if (map.containsKey(c)) {
               
                //如果曾经出现的 字母 还在窗口内 —— l更新到 该位置+1
                //如果曾经出现的 字母 已不在当前窗口内了—— 则不需要更新
                l = Math.max(l,map.get(c)+1);
            
            }
            map.put(c, r); // 更新当前字符的最后出现位置为当前索引r
            ans = Math.max(ans, r - l + 1); // 更新最长不重复子串的长度
        }
        
        return ans; // 返回最长不重复子串的长度
    }
}

要理解 left = Math.max(left,map.get(s.charAt(i)) + 1);需要回归到滑动窗口的原理上。

窗口中始终是无重复字母的字符串。 我们通过窗口的左界和右界控制窗口。

右界不用特意操作,因为它是+1,+1地涨上去,记得在循环里+1就好。

左界:每当有一个字符曾经出现过,就需要判断左界。

重点来了:

若,被判断的字符上一次出现的位置就在滑动窗口内,即 [ i,j ] 内, 则需要left改变位置,改变为该字符上次出现位置+1。也就是left = map.get(s.charAt(i)) + 1的情况。

例如:

abcdb中,窗口正常运行到abcd时,下一个字符为b,b上一次出现在实在窗口里,所以需要把left设置为上一次出现的位置+1的位置,得到新的窗口为cdb,不然你不这样设置,窗口里有重复的字符(bcdb),不符合窗口的定义。

若,不在滑动窗口内,则不用管。 不用管是因为:窗口中字符串没有重复字符。窗口符合定义。所以left = left。 left = left就表示这个窗口暂时不变。

在这里插入图片描述


  • 第二版优化的滑动窗口:
class Solution {
    public int lengthOfLongestSubstring(String s) {
        // 记录字符上一次出现的位置
        int[] last = new int[128]; // 创建一个长度为128的整型数组,用来记录ASCII码表中每个字符上一次出现的位置
        for(int i = 0; i < 128; i++) {
            last[i] = -1; // 初始化数组,所有字符的上一次出现位置都设为-1,表示尚未出现过
        }
        int n = s.length(); // 字符串s的长度

        int res = 0; // 用于记录最长的不重复子串的长度
        int start = 0; // 窗口开始位置,用来维护当前不重复子串的起始位置
        for(int i = 0; i < n; i++) {
            int index = s.charAt(i); // 获取当前字符的ASCII码作为索引
            start = Math.max(start, last[index] + 1); // 更新窗口的起始位置,确保不重复的起点
            res = Math.max(res, i - start + 1); // 更新最大的不重复子串长度
            last[index] = i; // 更新当前字符的最后出现位置为当前索引i
        }

        return res; // 返回最长的不重复子串的长度
    }
}

3.LeetCode 187 重复的DNA序列

在这里插入图片描述

  • 哈希表法~
class Solution {
    public List<String> findRepeatedDnaSequences(String s) {
        List<String> ans = new ArrayList<>(); // 用于存放重复的DNA序列
        int n = s.length(); 
        if (n < 10) return ans; // 如果字符串长度小于10,直接返回空列表,因为无法形成长度为10的序列
        Map<String, Integer> map = new HashMap<>(); // 创建一个哈希表,用来记录每个长度为10的子序列及其出现的次数
        map.put(s.substring(0, 10), 1); // 初始化,将第一个长度为10的子序列放入哈希表中
        
        for (int i = 1; i + 10 <= n; i++) { // 从第二个子序列开始遍历到倒数第十个子序列
            String ss = s.substring(i, i + 10); // 获取当前长度为10的子序列
            if (map.getOrDefault(ss, 0) == 1) { // 如果该子序列已经在哈希表中出现过一次
                ans.add(ss); // 将该子序列加入结果列表
            }
            map.put(ss, map.getOrDefault(ss, 0) + 1); // 更新哈希表中该子序列的出现次数
        }
        
        return ans; // 返回重复的DNA序列列表
    }
}
  • 滑动窗口法~
class Solution {
    // 滑动窗口法查找重复的长度为10的DNA序列
    public List<String> findRepeatedDnaSequences(String s) {
        List<String> ans = new ArrayList<>(); // 用于存放重复的DNA序列
        int n = s.length(); // 字符串的长度
        if (n < 10) return ans; // 如果字符串长度小于10,直接返回空列表,因为无法形成长度为10的序列

        StringBuilder sb = new StringBuilder(s.substring(0, 10)); // 初始化第一个长度为10的子串
        Set<String> set = new HashSet<>(); // 使用集合来记录出现过的子串
        set.add(sb.toString()); // 将第一个子串添加到集合中

        for (int i = 1; i + 10 <= n; i++) {
            String str = s.substring(i, i + 10); // 获取当前长度为10的子串

            if (set.contains(str)) { // 如果集合中已经包含当前子串
                if (!ans.contains(str)) // 且列表中还未包含该子串
                    ans.add(str); // 将该子串添加到列表中
            } else { // 如果集合中不包含当前子串
                set.add(str); // 将当前子串添加到集合中
            }
        }

        return ans; // 返回存放了重复DNA序列的列表
    }
}


4.LeetCode 424 替换后的最长重复字符

在这里插入图片描述
在这里插入图片描述

  • 核心思想:

相同的最长子字符串(窗口) = 窗口内最大字符个数 + 反转次数

一旦 窗口长度 - 窗口内最大字符个数 > 反转次数 窗口开始移动

public int characterReplacement(String s, int k) {
        int n = s.length();
        if(n<2) return n;
        int ans = 0; // 用于存储最长连续相同字符的子串的长度
        int maxFreq = 0; // 用于存储当前窗口内出现次数最多的字符的次数
        char[] c = s.toCharArray();
        int[] freq = new int[26]; // 记录当前窗口内每个字符出现的次数
        int left = 0; // 滑动窗口的左边界

        for (int right = 0; right < n; right++) {
            ++freq[c[right] - 'A']; // 更新右边界字符的出现次数
            maxFreq = Math.max(maxFreq, freq[c[right] - 'A']); // 更新最大出现次数

            // 如果当前窗口的大小减去出现次数最多的字符的次数大于k,则需要缩小窗口
            // 使得窗口内可以通过替换字符使其变成连续相同字符的子串
            if (right - left + 1 > maxFreq + k) {
                freq[c[left] - 'A']--; // 缩小窗口时,更新左边界字符的出现次数
                left++; // 缩小窗口
            }

            // 更新最长连续相同字符的子串的长度
            ans = Math.max(ans, right - left + 1);
        }
        return ans;
    }

5.LeetCode 438 找到字符串中所有字母异位词

在这里插入图片描述

  • 详细的思路都在注释里面了哈~
 public List<Integer> findAnagrams(String s, String p) {
        //在长度为26的int数组target中存储字符串p中对应字符(a~z)出现的次数
        //如p="abc",则target为[1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
        //如p="bbdfeee",则target为[0,2,0,1,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
        int[] target = new int[26];
        for (int i = 0; i < p.length(); i++) {
            target[p.charAt(i) - 'a']++;
        }
        //双指针构建滑动窗口原理:
        //1.右指针right先向右滑动并在window中存储对应字符出现次数
        //2.当左右指针间的字符数量(包括左右指针位置的字符)与p长度相同时开始比较
        //3.比较完成后,左右指针均向右滑动一位,再次比较
        //4.以后一直重复2、3,直到end指针走到字符串s的末尾
        int left = 0, right = 0;
        int[] window = new int[26];//构建一个与target类似的,存储了字符串s从left位置到right位置的窗口中字符对应出现次数的数组
        List<Integer> ans = new ArrayList<Integer>();
        while (right < s.length()) {
            window[s.charAt(right) - 'a']++;//每次右指针right滑动,字符串s的right位置的字符出现次数加1
            if (right - left + 1 == p.length()) {
                if (Arrays.equals(window, target)) ans.add(left);//通过Arrays.equals方法,当window数组与target数组相等即为异或词
                window[s.charAt(left) - 'a']--;//比较完成后,字符串s的left位置的字符出现次数减1(减1是因为左指针下一步要向右滑动)
                left++;//左指针向右滑动
            }
            right++;//右指针向右滑动
        }
        return ans;
    }

6.LeetCode 567 字符串的排列

在这里插入图片描述

这道题其实跟上一题有异曲同工之妙~🤣

  • 直接贴代码啦~ 思路在注释里~
class Solution {
    public boolean checkInclusion(String s1, String s2) {
        int n = s2.length();
        if (n < s1.length())
            return false; // 如果 s2 的长度小于 s1 的长度,直接返回 false,因为无法包含 s1 的排列

        int[] target = new int[26]; // 目标字符串 s1 的字符频率统计数组
        for (char c : s1.toCharArray()) {
            ++target[c - 'a']; // 统计 s1 中每个字符的出现次数
        }

        int l = 0, r = 0;
        int[] window = new int[26]; // 滑动窗口中的字符频率统计数组
        while (r < n) {
            ++window[s2.charAt(r) - 'a']; // 将 s2 中当前右边界字符加入窗口,并增加计数

            if (r - l + 1 == s1.length()) { // 当窗口大小等于 s1 的长度时进行判断
                if (Arrays.equals(target, window)) {
                    return true; // 如果窗口内的字符频率与 s1 相同,则找到了 s1 的一个排列,返回 true
                } else {
                    --window[s2.charAt(l) - 'a']; // 否则,移动左边界,将左边界字符移出窗口,并减少计数
                    ++l; // 左边界右移,缩小窗口
                }
            }
            ++r; // 右边界右移,扩大窗口
        }
        return false; // 扫描完整个字符串 s2 后没有找到 s1 的排列,返回 false
    }
}


更新于:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/770180.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

RPC远程过程调用--Thrift

RPC远程过程调用–Thrift 简介 Thrift是一个由Facebook开发的轻量级、跨语言的远程服务调用框架&#xff0c;后进入Apache开源项目。支持通过自身接口定义语言IDL定义RPC接口和数据类型&#xff0c;然后通过编译器生成不同语言代码&#xff0c;用于构建抽象易用、可互操作的R…

JAVA+SSM+VUE《教学视频点播系统》

1管理员登录 管理员登录&#xff0c;通过填写用户名、密码、角色等信息&#xff0c;输入完成后选择登录即可进入视频点播系统&#xff0c;如图1所示。 图1管理员登录界面图 2管理员功能实现 2.1 修改密码 管理员对修改密码进行填写原密码、新密码、确认密码并进行删除、修改…

【Python机器学习】算法链与管道——在网格搜索中使用管道

在网格搜索中使用管道的工作原理与使用任何其他估计器都相同。 我们定义一个需要搜索的参数网络&#xff0c;并利用管道和参数网格构建一个GridSearchCV。不过在指定参数网格时存在一处细微的变化。我们需要为每个参数指定它在管道中所属的步骤。我们要调节的两个参数C和gamma…

监控与安全服务

kali 系统 nmap扫描 网段的扫描 使用脚本扫描 使用john破解密码 哈希算法是一种单向加密的算法&#xff0c;也就是将原始数据生成一串“乱码”只能通过原始数据&#xff0c;生成这串“乱码”&#xff0c;但是不能通过“乱码”回推出原始数据相同的原始数据&#xff0c;生成的乱…

红酒与时尚秀场:品味潮流新风尚

在时尚与品味的交汇点上&#xff0c;红酒总是以其不同的方式&#xff0c;为每一次的时尚盛宴增添一抹诱人的色彩。当红酒遇上时尚秀场&#xff0c;不仅是一场视觉的盛宴&#xff0c;更是一次心灵的触动。今天&#xff0c;就让我们一起走进红酒与时尚秀场的世界&#xff0c;感受…

Elasticsearch:结合稀疏、密集和地理字段

作者&#xff1a;来自 Elastic Madhusudhan Konda 如何以自定义方式组合多个稀疏、密集和地理字段 Elasticsearch 是一款强大的工具&#xff0c;可用于近乎实时地搜索和分析数据。作为开发人员&#xff0c;我们经常会遇到包含各种不同字段的数据集。有些字段是必填字段&#x…

算法力扣刷题记录 二十八【225. 用队列实现栈】

前言 栈和队列篇。 记录 二十八【225. 用队列实现栈】 一、题目阅读 请你仅使用两个队列实现一个后入先出&#xff08;LIFO&#xff09;的栈&#xff0c;并支持普通栈的全部四种操作&#xff08;push、top、pop 和 empty&#xff09;。 实现 MyStack 类&#xff1a; void p…

数据库安全审计系统:满足数据安全治理合规要求

伴随着数据库信息价值以及可访问性提升&#xff0c;使得数据库面对来自内部和外部的安全风险大大增加&#xff0c;如违规越权操作、恶意入侵导致机密信息窃取泄漏&#xff0c;但事后却无法有效追溯和审计。 国内专注于保密与非密领域的分级保护、等级保护、业务连续性安全和大数…

浅谈渗透测试实战

很多时候&#xff0c;在看白帽子们的漏洞的时候总有一种感觉就是把web渗透简单地理解成了发现web系统漏洞进而获取webshell。其实&#xff0c;个人感觉一个完整的渗透&#xff08;从黑客的角度去思考问题&#xff09;应该是以尽一切可能获取目标的系统或者服务器的最高权限&…

TCL中环可转债缩水近90亿:业绩持续承压,百亿自有资金购买理财

《港湾商业观察》廖紫雯 日前&#xff0c;TCL中环新能源科技股份有限公司&#xff08;以下简称&#xff1a;TCL中环&#xff0c;002129.SZ&#xff09;可转债总额缩水近90亿&#xff0c;引发市场关注。可转债大幅缩水的另一面&#xff0c;公司此前发布公告披露将使用百亿自有资…

深入详解RocketMQ源码安装与调试

1.源码下载 http://rocketmq.apache.org/dowloading/releases/ 2. 环境要求 64位系统JDK1.8(64位)Maven 3.2.x

[笔记] 卷积03 - 运算的对称性 时域构建高通滤波器的失败尝试

1.卷积运算具备足够好的对称性 1.在计算卷积时&#xff0c;两个函数的位置是可以颠倒的&#xff0c;对吧&#xff1f; 在卷积运算中&#xff0c;确实可以对参与卷积的两个函数进行颠倒。这是因为卷积的定义是通过一个函数与另一个函数的翻转后的形式进行积分运算。具体来说&a…

【系统架构设计师】计算机组成与体系结构 ⑨ ( 磁盘管理 | “ 磁盘 “ 单缓冲区 与 双缓冲区 | “ 磁盘 “ 单缓冲区 与 双缓冲区案例 )

文章目录 一、" 磁盘 " 单缓冲区 与 双缓冲区1、" 磁盘 " 单缓冲区2、" 磁盘 " 双缓冲区 二、" 磁盘 " 单缓冲区 与 双缓冲区案例1、案例描述2、磁盘单缓冲区 - 流水线分析3、磁盘双缓冲区 - 流水线分析 一、" 磁盘 " 单缓冲…

Avalonia应用在基于Linux的国产操作deepin上运行

deepin系统介绍 deepin(原名Linux Deepin)致力于为全球用户提供美观易用&#xff0c;安全可靠的 Linux发行版。deepin项目于2008年发起&#xff0c;并在2009年发布了以 linux deepin为名称的第一个版本。2014年4月更名为 deepin&#xff0c;在中国常被称为“深度操作系统”。 …

matlab 干涉图仿真

目录 一、算法概述1、干涉图2、生成步骤 二、代码实现三、结果展示 本文由CSDN点云侠原创&#xff0c;原文链接。如果你不是在点云侠的博客中看到该文章&#xff0c;那么此处便是不要脸的爬虫。 一、算法概述 1、干涉图 干涉图是两束或多束相干光波相遇时&#xff0c;它们的振…

大模型学习笔记3【大模型】LLaMA学习笔记

文章目录 学习内容LLaMALLaMA模型结构LLaMA下载和使用好用的开源项目[Chinese-Alpaca](https://github.com/ymcui/Chinese-LLaMA-Alpaca)Chinese-Alpaca使用量化评估 学习内容 完整学习LLaMA LLaMA 2023年2月&#xff0c;由FaceBook公开了LLaMA&#xff0c;包含7B&#xff0…

echarts柱状选中shadow阴影背景宽度设置

使用line&#xff0c;宽度增大到所需要的宽度&#xff0c;设置下颜色透明度就行 tooltip: {trigger: axis,//把阴影的层级往下降z:-15,axisPointer: {type: line,lineStyle: {color: rgba(150,150,150,0.3),width: 44,type: solid,},}, }, series: [{type: bar,barWidth:20,//…

探究Executors创建的线程池(如newFixedThreadPool)其核心线程数等参数的可调整性

java中提供Executors类来创建一些固定模板参数的线程池&#xff0c;如下图&#xff08;newWorkStealingPool除外&#xff0c;这个是创建ForkJoinPool的&#xff0c;这里忽略&#xff09;&#xff1a; 拿newFixedThreadPool方法创建线程池为例&#xff0c;newFixedThreadPool是…

24位DAC转换的FPGA设计及将其封装成自定义IP核的方法

在vivado设计中,为了方便的使用Block Desgin进行设计,可以使用vivado软件把自己编写的代码封装成IP核,封装后的IP核和原来的代码具有相同的功能。本文以实现24位DA转换(含并串转换,使用的数模转换器为CL4660)为例,介绍VIVADO封装IP核的方法及调用方法,以及DAC转换的详细…

【WEB前端2024】3D智体编程:乔布斯3D纪念馆-第54课-poplang语音编程控制机器人

【WEB前端2024】3D智体编程&#xff1a;乔布斯3D纪念馆-第54课-poplang语音编程控制机器人 使用dtns.network德塔世界&#xff08;开源的智体世界引擎&#xff09;&#xff0c;策划和设计《乔布斯超大型的开源3D纪念馆》的系列教程。dtns.network是一款主要由JavaScript编写的…