滑动窗口思想(数组)-python

news2024/11/14 1:31:38

文章目录

  • 前言
  • 一、思想
  • 二、相关题目讲解
    • 1.长度最小的子数组(leetcode 209.)
    • 2.水果成篮(leetcode 904.)
    • 3.最小覆盖子串(leetcode 76.)
  • 三、 模拟行为
    • 螺旋矩阵II(leetcode.59)
    • leetcode 54.螺旋矩阵
    • 剑指Offer 29. 顺时针打印矩阵
  • 总结


前言

滑动窗口的精妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置。从而将O(n2 )的暴力解法降为O(n)。主要要理解滑动窗口如何移动窗口起始位置,达到动态更新窗口大小的,从而得出长度最小的符合题目条件的长度。


一、思想

那么滑动窗口是如何用一个for循环来完成整个操作的呢?
首先思考用一个for循环,那么应该表示滑动窗口的起始位置,还是终止位置。
如果只用一个for循环来控制滑动窗口的起始位置,那么剩下的终止位置如何遍历?这就又回到了暴力解法。
所以只用一个for循环的话,那么这个循环的索引,一定是表示滑动窗口的终止位置。那么滑动窗口的起始位置如何操作移动呢?
实现滑动窗口,主要确定如下三点:
(1) 窗口内是什么?
(2) 如何移动窗口的起始位置?
(3) 如何移动窗口的结束位置?
窗口就是满足长度最小的符合题目条件的连续子数组。
窗口的起始位置如何移动:如果当前窗口的值大于s了,窗口就要向前移动了(也就是该缩小了)。
窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。
在这里插入图片描述
通过这个图例可以体会到滑动窗口的精妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置。从而将O(n2 )暴力解法降为O(n)。

二、相关题目讲解

1.长度最小的子数组(leetcode 209.)

代码如下(示例):

class Solution:
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        l=len(nums)
        left=0
        right=0
        min_len=float('inf')#正无穷
        cur_sum=0      
        for right in range(0,l):
            cur_sum += nums[right]            
            while cur_sum >= target: # 当前累加值大于目标值
                min_len = min(min_len, right - left + 1)
                cur_sum -= nums[left]
                left += 1   #移动滑动窗口起始位置         
            right += 1  #移动滑动窗口结束位置       
        return min_len if min_len != float('inf') else 0

时间复杂度是O(n),有同学可能会问为什么不是O(n2 )呢,因为一个for循环下,虽然里面还放一个while循环,但是主要看每一个元素被操作的次数,每个元素在滑动窗后进来操作一次,出去操作一次,每个元素都是被操作两次,所以时间复杂度是 2 × n 也依旧是O(n)。

2.水果成篮(leetcode 904.)

代码如下(示例):

class Solution:
    def totalFruit(self, fruits: List[int]) -> int:
        l=len(fruits)
        left=0
        res=0
        classMap=defaultdict(int)#
        classCnt=0
        for right in range(0,l):
            if classMap[fruits[right]]==0:
                classCnt+=1
            classMap[fruits[right]]+=1
            while classCnt>2:
                if classMap[fruits[left]]==1:
                    classCnt-=1
                classMap[fruits[left]]-=1
                left+=1
                #一旦满足条件,更新结果
            res = max(res, right - left + 1)
        return res

本题区别于76题,这道题求的是最大滑窗,最大滑窗模版:给定数组 nums,定义滑窗的左右边界 left, right,求满足某个条件的滑窗的最大长度。关键的区别在于,最大滑窗是在迭代右移右边界的过程中更新结果,而最小滑窗是在迭代右移左边界的过程中更新结果。因此虽然都是滑窗,但是两者的模板和对应的贪心思路并不一样。

while right < len(nums):#滑动窗口结束位置的遍历
    判断[left, right]是否满足条件
    while 不满足条件:
        left += 1 (最保守的压缩i,一旦满足条件了就退出压缩i的过程,使得滑窗尽可能的大)
    不断更新结果(注意在while外更新!)
    right+= 1

3.最小覆盖子串(leetcode 76.)

class Solution:
    def minWindow(self, s: str, t: str) -> str:
    	from collections import Counter#快速计数
    	template_dict=Counter(t)#统计目标字符串里各字符的个数
    	window_dict={}#定义了一个滑动窗口字典
    	for each_key in template_dict:#对于目标字符串的每个字符
    		if each_key not in window_dict:#如果不在滑动窗口里
    			window_dict[each_key]=0#就赋值为零
    	def isContains(cur_dict,tmp_dict):
    		for each_key in tmp_dict:
    			if cur_dict[each_key]<tmp_dict[each_key]:#如果滑动窗口
    				return False
    		return True
    	start=0#定义滑动窗口起始位置
    	min_len=float('inf')#定义滑动窗口长度
    	res=''
    	for end in range(len(s)):#滑动窗口结束位置的遍历
    		if s[end] in template_dict:#如果字符串的字符出现在目标字符串里
    			window_dict[s[end]]+=1#滑动窗口对应字符附值+1
    		while isContains(window_dict,template_dict):#滑动窗口满足目标要求
    			if min_len>end-start+1
    				min_len=end-start+1
    				res=s[start:end+1]
    			if s[start] in window_dict:
    				window_dict[s[start]]-=1
    			start+=1
    	return res

本题是最小滑窗思路,最小滑窗模板:给定数组 nums,定义滑窗的左右边界 left, right,求满足某个条件的滑窗的最小长度。滑动窗口简单说就是右指针先出发,左指针视情况追赶右指针。因此,右指针最多遍历一遍数组,左指针也最多遍历一次数组,时间复杂度不超过O(2N)。接下来,如何判断滑动窗口内是否满足题设条件,有两种选择:(1) 要么你遍历这个滑窗,通过遍历来断滑窗是否满足需要O(N), 那么总的时间就退化为O(N2), (2) 要么你选择字典,用空间换时间,那么判断划窗是否满足条件则需要 O(1),总时间为O(N).

while right < len(nums):
    判断[eft, right]是否满足条件
    while 满足条件:
        不断更新结果(注意在while内更新!)
        left += 1 (最大程度的压缩i,使得滑窗尽可能的小)
    right += 1

三、 模拟行为

螺旋矩阵II(leetcode.59)

这道题在面试中出现频率较高,不涉及算法,就是模拟过程,考察候选人的代码能力
模拟顺时针画矩阵的过程:
上行从左到右
右列从上到下
下行从右到左
左列从下到上
由外向内一圈一圈这么画下去。

发现边界条件非常多,在一个循环中,如此多的边界条件,如果不按固定规则来遍历,就容易陷入循环陷阱。
思路:

startx=0,starty=0
offset=1
count=1
while(n/2){
	for(j=starty;j<n-offset;j++) #从左到右
		nums[startx][j]=count++;
	for(i=startx;i<n-offset;i++)#从上到下
		nums[i][j]=count++;
	for(j=n-offset;j>s;j--)#从右到左
		nums[i][j]=count++;
	for( ;i>startx;i--)
		nums[i][j]=count++;

具体实现代码:
在这里插入图片描述

class Solution:
    def generateMatrix(self, n: int) -> List[List[int]]:
        nums = [[0] * n for _ in range(n)]
        startx, starty = 0, 0               # 起始点
        loop, mid = n // 2, n // 2          # 迭代次数、n为奇数时,矩阵的中心点
        count = 1                           # 计数
        for offset in range(1, loop + 1) :      # 每循环一层偏移量加1,偏移量从1开始
            for i in range(starty, n - offset) :    # 从左至右,左闭右开
                nums[startx][i] = count
                count += 1
            for i in range(startx, n - offset) :    # 从上至下
                nums[i][n - offset] = count
                count += 1
            for i in range(n - offset, starty, -1) : # 从右至左
                nums[n - offset][i] = count
                count += 1
            for i in range(n - offset, startx, -1) : # 从下至上
                nums[i][starty] = count
                count += 1                
            startx += 1         # 更新起始点
            starty += 1

        if n % 2 != 0 :			# n为奇数时,填充中心点
            nums[mid][mid] = count 
        return nums

复杂度分析:时间复杂度:O(n2),其中 n是给定的正整数。矩阵的大小是 nxn,需要填入矩阵中的每个元素。
空间复杂度:O(1)。除了返回的矩阵以外,空间复杂度是常数。


leetcode 54.螺旋矩阵

class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        if not matrix or not matrix[0]:
            return list()        
        rows, columns = len(matrix), len(matrix[0])
        order = list()
        left, right, top, bottom = 0, columns - 1, 0, rows - 1
        while left <= right and top <= bottom:
            for column in range(left, right + 1):
                order.append(matrix[top][column])
            for row in range(top + 1, bottom + 1):
                order.append(matrix[row][right])
            if left < right and top < bottom:
                for column in range(right - 1, left, -1):
                    order.append(matrix[bottom][column])
                for row in range(bottom, top, -1):
                    order.append(matrix[row][left])
            left, right, top, bottom = left + 1, right - 1, top + 1, bottom - 1
        return order

时间复杂度:O(mn),其中 m 和 n分别是输入矩阵的行数和列数。矩阵中的每个元素都要被访问一次。
空间复杂度:O(1)。除了输出数组以外,空间复杂度是常数。


剑指Offer 29. 顺时针打印矩阵

class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        if not matrix or not matrix[0]:
            return list()
        
        rows, columns = len(matrix), len(matrix[0])
        order = list()
        left, right, top, bottom = 0, columns - 1, 0, rows - 1
        while left <= right and top <= bottom:
            for column in range(left, right + 1):
                order.append(matrix[top][column])
            for row in range(top + 1, bottom + 1):
                order.append(matrix[row][right])
            if left < right and top < bottom:
                for column in range(right - 1, left, -1):
                    order.append(matrix[bottom][column])
                for row in range(bottom, top, -1):
                    order.append(matrix[row][left])
            left, right, top, bottom = left + 1, right - 1, top + 1, bottom - 1
        return order

同样的解题思路,时间复杂度:O(mn),其中 m 和 n分别是输入矩阵的行数和列数。矩阵中的每个元素都要被访问一次。
空间复杂度:O(1)。除了输出数组以外,空间复杂度是常数。


总结

滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果。最容易想到的暴力解法,步骤是一个for循环控制滑动窗口的起始位置,另一个for循环控制滑动窗口的终止位置,用两个for循环完成了一个不断搜索区间的过程,时间复杂度是O(n2 )。而滑动窗口的精妙之处在于,用一个for循环完成区间的搜索,时间复杂度是O(n)。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

物业管理系统对小区物业的作用太重要了,零代码平台改变原有认知

小区物业处作为业主与小区的沟通场所&#xff0c;经常会遇到缺乏专业人才&#xff0c;导致管理不善、服务不到位&#xff0c;难以为业主提供良好的服务体验&#xff0c;那么拥有一款成熟稳定的物业管理系统就成了物业管理处的重要选择&#xff0c;不仅能为业主带来更好的服务体…

悦灵犀-全新的智能AI工具

最近一段时间&#xff0c;人工智能再次成为人类创新的焦点&#xff0c;不得不说&#xff0c;人工智能正在以一种全新的方式改变人们的生活&#xff0c;这是一个以大模型为核心的人工智能新时代&#xff0c;大模型的出现让千行百业将迎来新的机遇。 悦享星光作为国内高新技术企…

Zinx框架学习 - 构建最基础的Server

Zinx - V0.1 构建最基础的Server Zinx的框架结构&#xff1a; 整体思路&#xff1a; 客户端发送请求到服务器端&#xff0c;服务端会有一个Goroutine专门处理listenner和监听这个过程&#xff0c;然后有客户端连接过来之后会启动一个客户端处理Goroutine&#xff0c;这个Goro…

深度学习 - 52.推荐场景的多样性与 MMR [Maximal Marginal Relevance] 简介与 Python 实现

目录 一.引言 二.多样性 三.MMR 流程 1.标准 MMR 2.窗口 MMR 四.基于向量内积相似度的 MMR Python 实现 1.模拟用户 rank 结果 2.向量内积计算 MRi 2.1 获取向量计算 max sim 2.2 argmax 获取最优 MRi item 3.MMR 测试 4.MMR 完整代码 五.总结 一.引言 MMR - Ma…

记一次k8s节点上出现node.kubernetes.io/disk-pressure污点的问题

目录 问题描述 原因分析&#xff1a; 解决方案&#xff1a; 其他问题 问题描述 k8s部署时pod一直属于Pending状态&#xff0c;也就是说pod未调度到k8s节点上 原因分析&#xff1a; 通过以下命令查看下pod kubectl get pod 以上命令可以看到各个pod的状态&#xff0c…

【商城后台管理系统】项目初始化(UmiJS)

目录 一、运行时配置 1.1 配置方式 1.2 常用配置项 1.3 关于运行时配置说明 二、使用Umi UI 2.1 Umi UI的特性 2.2 项目中安装Umi UI 2.3 使用Umi UI 三、Umi JS总结 3.1 路由状态管理 3.2 配置代理 3.3 封装requset 一、运行时配置 运行时配置和配置的区别是他跑…

Geohash算法原理及实现

最近需要实现一个功能&#xff0c;查找车辆附近的加油站&#xff0c;如果车和加油站距离在200米以内&#xff0c;则查找成功。 加油站数量肯定不小&#xff0c;能否缩小查找范围&#xff0c;否则以遍历形式&#xff0c;效率肯定高不了。 Geohash算法就是将经纬度编码&#xf…

又名管道和无名管道

一、进程间通信&#xff08;IPC&#xff0c;InterProcess Communication&#xff09; 概念&#xff1a;就是进程和进程之间交换信息。 常用通信方式 无名管道&#xff08;pipe&#xff09; 有名管道 &#xff08;fifo&#xff09; 信号&#xff08;signal&#xff09; 共…

数字化时代,低代码+进销存管理系统让你省时省力

进销存系统是一种用于管理企业物资流动和库存的软件系统&#xff0c;可以帮助企业优化物资管理过程&#xff0c;提高效率&#xff0c;减少成本&#xff0c;从而提升企业的盈利能力。本文将详细介绍进销存系统的定义、功能、好处以及如何选择适合自己企业的进销存系统&#xff0…

【嵌入式烧录/刷写文件】-2.6-剪切/保留Intel Hex文件中指定地址范围内的数据

案例背景&#xff1a; 有如下一段HEX文件&#xff0c;保留地址范围0x9140-0x91BF内的数据&#xff0c;删除地址范围0x9140-0x91BF外的数据。 :2091000058595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F70717273747576775F :2091200078797A7B7C7D7E7F808182838485868788898A…

「ACL 2023」发榜!火山语音推出业内首个借助视频信息的端到端语音翻译模型

日前 ACL 2023的论文录用结果公布&#xff0c;火山语音团队多篇论文成功入选&#xff0c;内容涵盖音频合成、歌声合成以及语音翻译等多个前沿技术领域的创新突破。ACL&#xff08;Annual Meeting of the Association for Computational Linguistics&#xff09;每年由国际计算语…

Nginx服务器及其配置与应用

目录 一、Nginx的特点 1.高并发 2.低消耗 3.低消耗 4.高可用 5.高扩展 6.Nginx与Apache的差异 7.Nginx与Apache的区别 二、Linux中的I/O 1.I/O介绍 2.同步/异步 3.阻塞/非阻塞:关注调用者在等待结果返回之前所处的状态 三、编译安装Nginx服务 1.关闭防火墙&#…

SOLIDWORKS安装使用说明网络版

安装准备 系统要求&#xff1a;参考https://www.solidworks.com/sw/support/SystemRequirements.htmlSolidWorks 2017 是最蕞后一个支持win server 2008 R2 sp1的软件。 SolidWorks 2018支持win server 2012及以上的系统&#xff0c;但不支持win server 2019 SolidWorks 2019…

HNU-计算机系统-CSAPP作业答案

计算机系统CSAPP课后作业答案 计科210X wolf 202108010XXX 第2章 2.61 解: (!~x) || (!x) || (!~(x|0x00ffffff)) || (!(x&0x000000ff)) 或者: (!~x) || (!x) || (!~(x>>24)) || (!(x<<24)) 2.71 A. 实现的是逻辑位移,扩展后前面全是0,不符合符号扩…

Linux常见命令学习

目录 1.ls2.pwd3.cd (change directory)4.touch&&cat&&echo5.mkdir&&rm6.cp&&mv7.man8.less&&vim 1.ls 列出当前目录中包含的文件和目录~ 类似于在windows上双击某个目录&#xff0c;把他打开&#xff0c;看看目录里有啥~ ls -> l…

企业内容管理丨如何解决企业客户签收回执慢,缩短回款周期?

方案应用领域及行业 本方案适用于快消品行业的供应链管理和财务管理 方案应用背景 由于动产物权的政策变化&#xff0c;物权转移从交付时才开始发生效力。也就是说&#xff0c;新政之前&#xff0c;企业发出商品&#xff0c;开出销售发票&#xff0c;即可申请货物回款&#…

C# webapi接口传输byte[]数据,报错:415 Unsupported Media Type

最近需要做上传文件操作。 由于历史原因&#xff0c;以前的接口使用了这样的入参&#xff1a; 代码如下&#xff1a; /// <summary> /// 上传文件 /// </summary> [HttpPost] public Result<UploadImageResult> UploadFile(byte[] bytes, string extName, s…

html框架-----标签(上)

目录 前言&#xff1a; 标签简介 1. HTML的基本结构 (1)html标签 (2)head标签 &#xff08;3&#xff09;body标签 2. 标题标签 3. 段落标签 4. 文本格式化标签 前言&#xff1a; 现在学前端工程师的都很难找工作&#xff0c;懂的都懂了&#xff0c;因为学前端一般去做那…

console.log是异步还是同步?为什么console.log有时候不准

console.log是异步还是同步 在前端开发中&#xff0c;控制台console.log通常是同步的。这意味着&#xff0c;当代码执行到console.log语句时&#xff0c;它会立即写入到控制台中&#xff0c;并且JavaScript代码执行会在console.log完成后继续进行。 但是&#xff0c;在某些情况…

# croc用法实践(设备间文件或文件夹传输)

croc用法实践&#xff08;设备间文件或文件夹传输&#xff09; 文章目录 croc用法实践&#xff08;设备间文件或文件夹传输&#xff09;1 安装2 使用示例2.1 发送文件2.2 发送文件夹2.3 发送文本字符串2.4 发送时指定code&#xff0c;接收时自动【Y】&#xff0c;并保存到指定目…