【leetcode】滑动窗口刷题总结

滑动窗口算法技巧主要用来解决子数组问题,比如让你寻找符合某个条件的最长/最短子数组或者子串。对于某些题目,并不需要穷举所有子串,就能找到题目想要的答案。滑动窗口就是这种场景下的一套算法模板,帮你对穷举过程进行剪枝优化,将求解子串复杂度由O(N^2)->O(N)

滑动窗口-定长滑动窗口

定长滑窗三步曲:入-更新-出

  • 入(扩大窗口):下标为 i 的元素进入窗口,更新相关统计量
  • 更新:更新答案,一般是更新最大值/最小值
  • 出(更新窗口):下标为 i−k+1 的元素离开窗口,更新相关统计量

LeetCode1456题 定长子串中元音的最大数目

class Solution:
    def maxVowels(self, s: str, k: int) -> int:
        res = num = 0
        for i in range(len(s)):
            # 入
            if s[i] in 'aeiou':
                num += 1
            # 长度不足,继续向前
            if i < k - 1:
                continue
            # 更新
            res = max(res, num)
            # 出
            if s[i - k + 1] in 'aeiou':
                num -= 1
        return res

 LeetCode438题 找到字符串中所有字母异位词

class Solution:
    def findAnagrams(self, s: str, p: str) -> List[int]:
        res = []
        need_dict = dict()
        for s_ in p:
            need_dict[s_] = need_dict.get(s_, 0) + 1
        satisfy_num = 0
        for right in range(len(s)):
            # 入
            if s[right] in need_dict:
                need_dict[s[right]] -= 1
                if need_dict[s[right]] == 0:
                    satisfy_num += 1
            if right < len(p) - 1:
                continue
            # 更新
            if satisfy_num == len(need_dict):
                res.append(right - len(p) + 1)
            # 出
            if s[right - len(p) + 1] in need_dict:
                need_dict[s[right - len(p) + 1]] += 1
                if need_dict[s[right - len(p) + 1]] == 1:
                    satisfy_num -= 1
        return res

LeetCode30题 串联所有单词的子串

“找到字符串中所有字母异位词”的升级版,将“字母异位”升级为“单词异位”。首先需要将s划分为单词组,每个单词的大小均为n,这样的划分方法有n种,即先删去前i (i=0∼n−1)个字母后,将剩下的字母进行划分,如果末尾有不到 n 个字母也删去。对这n种划分得到的单词数组分别使用滑动窗口对words进行类似于「字母异位词」的搜寻

class Solution:
    def findSubstring(self, s: str, words: List[str]) -> List[int]:
        res = []
        m, n = len(words), len(words[0])
        for i in range(n):
            # 初始化变量
            need_dict = dict()
            satisfy_num = 0
            for w in words:
                need_dict[w] = need_dict.get(w, 0) + 1
            # 滑动窗口
            for right in range(i, len(s)):
                # 入
                if (right - i + 1) % n == 0:
                    s_ = s[right - n + 1: right + 1]
                    if s_ in need_dict:
                        need_dict[s_] -= 1
                        if need_dict[s_] == 0:
                            satisfy_num += 1
                if right - i + 1 < m * n:
                    continue
                # 更新
                if satisfy_num == len(need_dict):
                    res.append(right - m * n + 1)
                # 出
                if (right - i + 1) % n == 0:
                    s_ = s[right - m * n + 1: right - n * m + n + 1]
                    if s_ in need_dict:
                        need_dict[s_] += 1
                        if need_dict[s_] == 1:
                            satisfy_num -= 1
        return res

滑动窗口-不定长滑动窗口-求最长子数组/子串

LeetCode3题 无重复字符的最长子串

  • 窗口就是无重复字符的连续子串
  • 窗口的起始位置如何移动:如果当前窗口不满足条件,窗口起始位置就要向前移动
  • 窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针
class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        res = 0
        left = 0
        visited = dict()
        for right in range(len(s)):
            # 入
            visited[s[right]] = visited.get(s[right], 0) + 1
            # 出:当不满足条件时,需要持续向右移动left指针
            while visited[s[right]] > 1:
                visited[s[left]] -= 1
                left += 1
            # 更新:统计加入s[right]时满足条件的子串长度
            res = max(res, right - left + 1)
        return res

LeetCode904题 水果成篮

class Solution:
    def totalFruit(self, fruits: List[int]) -> int:
        res = 0
        left = 0
        window_fruits = dict()
        window_num = 0
        for right in range(len(fruits)):
            # 入
            window_fruits[fruits[right]] = window_fruits.get(fruits[right], 0) + 1
            window_num += 1
            # 出
            while len(window_fruits) >= 3:
                window_fruits[fruits[left]] -= 1
                if window_fruits[fruits[left]] == 0:
                    del window_fruits[fruits[left]]
                left += 1
                window_num -= 1
            # 更新
            res = max(res, window_num)
        return res

LeetCode395题 至少有K个字符的最长子串

我们枚举最长子串中的字符种类数目,它最小为 1,最大为26。对于给定的字符种类数量,我们维护滑动窗口的左右边界、滑动窗口内部每个字符出现的次数,以及滑动窗口内的字符种类数。当 种类数超过设定时,我们不断地右移左边界,并对应地更新其他变量,并记录下符合条件的最长子串

class Solution:
    def longestSubstring(self, s: str, k: int) -> int:
        res = 0
        for max_char_num in range(1, 27):
            left = 0
            window_count = dict()
            satisfy_num = 0
            for right in range(len(s)):
                # 入
                window_count[s[right]] = window_count.get(s[right], 0) + 1
                if window_count[s[right]] == k:
                    satisfy_num += 1
                # 出
                while len(window_count) > max_char_num:
                    window_count[s[left]] -= 1
                    if window_count[s[left]] == k - 1:
                        satisfy_num -= 1
                    if window_count[s[left]] == 0:
                        del window_count[s[left]]
                    left += 1
                # 更新
                if satisfy_num == len(window_count):
                    res = max(res, right - left + 1)
        return res

滑动窗口-不定长滑动窗口-求最短子数组/子串

LeetCode76题 最小覆盖子串

class Solution:
    def minWindow(self, s: str, t: str) -> str:
        res = ''
        # 记录需要覆盖的字母数量
        need = dict()
        for i in t:
            need[i] = need.get(i, 0) + 1
        # 记录覆盖的字母数量
        cover = 0
        # 初始化左边界
        left = 0
        for right in range(len(s)):
            # 入
            if s[right] in need:
                need[s[right]] -= 1
                if need[s[right]] == 0:
                    cover += 1
            # 出:当满足条件时,记录覆盖字串,同时开始将左侧指针右移
            while cover == len(need):
                # 更新结果
                if right - left + 1 < len(res) or len(res) == 0:
                    res = s[left: right + 1]
                if s[left] in need:
                    need[s[left]] += 1
                    if need[s[left]] == 1:
                        cover -= 1
                left += 1
        return res

LeetCode209题 长度最小的子数组

  • 窗口就是满足和>=target的连续子数组
  • 窗口的起始位置如何移动:如果当前窗口的值>=target,窗口就要向右移动
  • 窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针
class Solution:
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        res = len(nums) + 1
        window_sum = 0
        left = 0
        for right in range(len(nums)):
            # 入
            window_sum += nums[right]
            # 出
            while window_sum >= target:
                # 更新
                res = min(res, right - left + 1)
                window_sum -= nums[left]
                left += 1
        if res == len(nums) + 1:
            return 0
        else:
            return res

LeetCode632题 最小区间

排序 + 滑动窗口:把所有元素都合在一起排序,可以得到(元素值,所属列表编号)组成的数组,合法区间等价于排序后的一个连续子数组,满足列表编号0~k-1都在这个子数组中。由于子数组越长,越能包含所有编号,有单调性,可以用滑动窗口解决

class Solution:
    def smallestRange(self, nums: List[List[int]]) -> List[int]:
        sorted_nums = sorted([(x, i) for i, arr in enumerate(nums) for x in arr])
        cover_count = dict()
        res = [-10**5, 10**5]
        left = 0
        for right in range(len(sorted_nums)):
            # 入
            cover_count[sorted_nums[right][1]] = cover_count.get(sorted_nums[right][1], 0) + 1
            while len(cover_count) == len(nums):
                # 更新
                l, r = sorted_nums[left][0], sorted_nums[right][0]
                if r - l < res[1] - res[0] or (r - l == res[1] - res[0] and l < res[0]):
                    res = [l, r]
                # 出
                cover_count[sorted_nums[left][1]] -= 1
                if cover_count[sorted_nums[left][1]] == 0:
                    del cover_count[sorted_nums[left][1]]
                left += 1
        return res

滑动窗口-不定长滑动窗口-求子数组个数

LeetCode1358题 包含所有三种字符的子字符串数目

越长越合法:平移左指针,不断调整右指针位置直到符合条件,右指针右侧都是符合条件的子数组

class Solution:
    def numberOfSubstrings(self, s: str) -> int:
        res = 0
        right = 0
        window_count = dict()
        for left in range(len(s)):
            # 入
            while len(window_count) < 3 and right < len(s):
                window_count[s[right]] = window_count.get(s[right], 0) + 1
                right += 1
            # 更新
            if len(window_count) == 3:
                res += len(s) - right + 1
            # 出
            window_count[s[left]] -= 1
            if window_count[s[left]] == 0:
                del window_count[s[left]]
        return res

LeetCode713题 乘积小于K的子数组

越短越合法:平移右指针,不断调整左指针位置直到符合条件,左指针右侧都是符合条件的子数组

class Solution:
    def numSubarrayProductLessThanK(self, nums: List[int], k: int) -> int:
        res = 0
        window_res = 1
        left = 0
        for right in range(len(nums)):
            # 入
            window_res *= nums[right]
            # 出
            while window_res >= k and left <= right:
                window_res /= nums[left]
                left += 1
            # 更新
            res += right - left + 1
        return res

 LeetCode930题 和相同的二元子数组

要计算有多少个元素和恰好等于k的子数组,可以把问题变成:

  • 计算有多少个元素和<=k的子数组
  • 计算有多少个元素和<=k-1的子数组

然后将两个值相减,就是答案

class Solution:
    def numSubarraysWithSum(self, nums: List[int], goal: int) -> int:
        return self.sliding_window(nums, goal) - self.sliding_window(nums, goal - 1)

    def sliding_window(self, nums, k):
        # 和<=k的子数组个数
        res = 0
        window_sum = 0
        left = 0
        for right in range(len(nums)):
            window_sum += nums[right]
            while window_sum > k and left <= right:
                window_sum -= nums[left]
                left += 1
            res += right - left + 1
        return res

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

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

相关文章

前端快速生成接口方法

大家好&#xff0c;我是苏麟&#xff0c;今天聊一下OpenApi。 官网 &#xff1a; umijs/openapi - npm 安装命令 npm i --save-dev umijs/openapi 在根目录&#xff08;项目目录下&#xff09;创建文件 openapi.config.js import { generateService } from umijs/openapi// 自…

云消息队列 ApsaraMQ Serverless 演进:高弹性低成本、更稳定更安全、智能化免运维

如今&#xff0c;消息队列已成为分布式架构中不可或缺的关键服务&#xff0c;为电商、物联网、游戏和教育等行业&#xff0c;提供了异步解耦、集成、高性能和高可靠的核心价值。 过去一年&#xff0c;我们发布了云消息队列 ApsaraMQ 全系列产品 Serverless 化&#xff0c;面向…

Spring依赖注入方式

写在前面&#xff1a;大家好&#xff01;我是晴空๓。如果博客中有不足或者的错误的地方欢迎在评论区或者私信我指正&#xff0c;感谢大家的不吝赐教。我的唯一博客更新地址是&#xff1a;https://ac-fun.blog.csdn.net/。非常感谢大家的支持。一起加油&#xff0c;冲鸭&#x…

Mysql索引失效的场景

对索引列使用函数或表达式&#xff0c;或参与计算&#xff08;优化方法&#xff1a;将计算移到条件右侧&#xff1a;&#xff09;例 优化 对索引列进行隐式类型转换&#xff0c;条件中的数据类型与索引列的数据类型不匹配&#xff0c;会进行隐式类型转换 以like 通配符开头索…

CTFHub-RCE系列wp

目录标题 引言什么是RCE漏洞 eval执行文件包含文件包含php://input读取源代码远程包含 命令注入无过滤过滤cat过滤空格过滤目录分隔符过滤运算符综合过滤练习 引言 题目共有如下类型 什么是RCE漏洞 RCE漏洞&#xff0c;全称是Remote Code Execution漏洞&#xff0c;翻译成中文…

算法学习笔记之并查集

简介 问题描述&#xff1a;将编号为1-N的N个对象划分为不相交集合&#xff0c;在每个集合中&#xff0c;选择其中的某个元素代表所在集合。 常见两种操作&#xff1a; 1.合并两个集合 2.查找某元素属于哪个集合 实现方法1 用编号最小的元素标记所在集合&#xff1b; 定义…

渗透利器工具:Burp Suite 联动 XRAY 图形化工具.(主动扫描+被动扫描)

Burp Suite 联动 XRAY 图形化工具.&#xff08;主动扫描被动扫描&#xff09; Burp Suite 和 Xray 联合使用&#xff0c;能够将 Burp 的强大流量拦截与修改功能&#xff0c;与 Xray 的高效漏洞检测能力相结合&#xff0c;实现更全面、高效的网络安全测试&#xff0c;同时提升漏…

菌贝:云南鸡枞菌走向世界的第一品牌

云南&#xff0c;这片神奇的土地&#xff0c;孕育了无数珍稀的野生菌&#xff0c;而鸡枞菌无疑是其中的佼佼者。它以其独特的口感和丰富的营养价值&#xff0c;被誉为“菌中之王”。在云南鸡枞菌的品牌化进程中&#xff0c;菌贝以其卓越的品质和广泛的影响力&#xff0c;成为云…

如何恢复使用 Command+Option+Delete 删除的文件:完整指南

在日常使用 Mac 时&#xff0c;我们经常会使用 CommandOptionDelete 组合键来快速删除文件。这种删除方式会将文件直接移出废纸篓&#xff0c;而不会经过废纸篓的中间步骤&#xff0c;因此文件看似被永久删除。然而&#xff0c;即使文件被这样删除&#xff0c;仍然有几种方法可…

windows生成SSL的PFX格式证书

生成crt证书: 安装openssl winget install -e --id FireDaemon.OpenSSL 生成cert openssl req -x509 -newkey rsa:2048 -keyout private.key -out certificate.crt -days 365 -nodes -subj "/CN=localhost" 转换pfx openssl pkcs12 -export -out certificate.pfx…

用户认证综合实验

实验需求 需求一&#xff1a;根据下表&#xff0c;完成相关配置 需求二&#xff1a;配置DHCP协议&#xff0c;具体要求如下 需求三&#xff1a;防火墙安全区域配置 需求四&#xff1a;防火墙地址组信息 需求五&#xff1a;管理员 为 FW 配置一个配置管理员。要求管理员可以通…

5.7.2 进度管理

文章目录 进度管理Gantt图PERT图 进度管理 进度安排&#xff1a;通过将项目分解成多个活动&#xff0c;分析活动间的依赖关系&#xff0c;估算工作量&#xff0c;分配资源&#xff0c;制定活动时序。 Gantt图 Gantt图横坐标表示时间&#xff0c;纵坐标表示不同任务。使用一条条…

MQTT(Message Queuing Telemetry Transport)协议(二)

下面为你详细介绍如何基于 TCP 协议对 MQTT 进行封装&#xff0c;包括实现思路、代码示例及代码解释。 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h>…

b站——《【强化学习】一小时完全入门》学习笔记及代码(1-3 多臂老虎机)

问题陈述 我们有两个多臂老虎机&#xff08;Multi-Armed Bandit&#xff09;&#xff0c;分别称为左边的老虎机和右边的老虎机。每个老虎机的奖励服从不同的正态分布&#xff1a; 左边的老虎机&#xff1a;奖励服从均值为 500&#xff0c;标准差为 50 的正态分布&#xff0c;即…

Unity 接入Tripo 文生模型,图生模型

官方网站&#xff1a;https://www.tripo3d.ai/app/home自行注册账号并且登陆下载Unity插件&#xff1a;https://cdn-web.tripo3d.ai/plugin/tripo-unity.zip申请apikey&#xff1a; https://platform.tripo3d.ai/api-keys使用&#xff08;后续过程就按照第二步下载的插件里面的…

Arduino 第十一章:温度传感器

Arduino 第十一章&#xff1a;LM35 温度传感器 一、LM35 简介 LM35 是美国国家半导体公司&#xff08;现德州仪器&#xff09;生产的一款精密集成电路温度传感器。与基于热力学原理的传统温度传感器不同&#xff0c;LM35 能直接将温度转换为电压输出&#xff0c;且输出电压与…

【并发控制、更新、版本控制】.NET开源ORM框架 SqlSugar 系列

系列文章目录 &#x1f380;&#x1f380;&#x1f380; .NET开源 ORM 框架 SqlSugar 系列 &#x1f380;&#x1f380;&#x1f380; 文章目录 系列文章目录一、并发累计&#xff08;累加&#xff09;1.1 单条批量累计1.2 批量更新并且字段11.3 批量更新并且字段list中对应的…

5 分钟用满血 DeepSeek R1 搭建个人 AI 知识库(含本地部署)

最近很多朋友都在问&#xff1a;怎么本地部署 DeepSeek 搭建个人知识库。 老实说&#xff0c;如果你不是为了研究技术&#xff0c;或者确实需要保护涉密数据&#xff0c;我真不建议去折腾本地部署。 为什么呢&#xff1f; 目前 Ollama 从 1.5B 到 70B 都只是把 R1 的推理能力…

opc da 服务器数据 转 EtherCAT项目案例

目录 1 案例说明 2 VFBOX网关工作原理 3 应用条件 4 查看OPC DA服务器的相关参数 5 配置网关采集opc da数据 6 启动EtherCAT从站转发采集的数据 7 在服务器上运行仰科OPC DA采集软件 8 案例总结 1 案例说明 在OPC DA服务器上运行OPC DA client软件查看OPC DA服务器的相…

微信小程序地图开发总结-规划路线

在现代移动应用中&#xff0c;地图导航功能已成为必不可少的一部分。通过地图 API&#xff0c;我们可以轻松地在应用中集成位置服务和路径规划功能。本篇文章将带大家一起实现一个简单的路径导航功能&#xff0c;使用腾讯地图 API结合微信小程序&#xff0c;实现从当前位置到目…