“滑动窗口”思想在算法里面的应用

news2024/11/14 20:51:55

目录

一· 无重复字符串的最长子串

链接:无重复字符的最长子串

 1. 题目分析

解法一:暴力求解

借助2个“指针”:left , right 指针,依次固定left  指针,让right指针进行遍历,每遇到一个最大的

字符串进行更新即可。

对应时间复杂度:O(N^2)

解法二:滑动窗口

2个指针移动方向一致,对right 指针所指向的元素进行遍历,对left 指针指向元素进行删除

此时借助一个临时数组判断是否有元素的重写。

2. 算法原理

暴力求解的草图:

模拟暴力求解的过程:

我们发现当出现重复元素的时候,每次right 指针重新回到新的left 所指向的

位置,在一次进行遍历的时候,求解最大长度的时候 只有2中可能的结果:要不就是等于初次的最

大长度;要不就是小于初次的最大长度

因为在[ left ,right ] 这个区间内left ++ 一次,都会让 [ left ,right ] 这个区间内l 元素的个数减少一

个。

因此我们可以进行优化当遇到重复元素的时候,让right 指针不动,移动left 指针。

这正是“滑动窗口 ” 的应用。

时间复杂度:O(N)

此时我们需要借助一个临时的数组,来判断当前的元素是否重复。

出窗口结束条件:right 所指向的元素没有出现过就可以 ,此时删除left  所指向的没有元素。

3.  OJ代码
class Solution {
public:
    int lengthOfLongestSubstring(string s)
     {
        //滑动窗口
        int left = 0,right = 0,n = s.size();
        int tmp[128] = {0};
        int len = 0;
        while(right < n)
        {
            //进窗口
          
            tmp[ s[right]] ++;
          
            //出窗口
            while( tmp[ s[right]] > 1)
            {
               
                tmp[ s[left]]--;//tmp 当前位置元素为0
                left++;
            }
               //更新
               len = max (right-left+1,len);
            right++;
        }
        return len;

    }
};

二· 最大连续1的个数

链接:最大连续1的个数

 

 1. 题目分析

常规思路就是:遍历数组,遇到数字0 就改写成数字1,并记录一下Count 的大小当Count == 0的

个数的时候,就是这个区间里面1的个数。

草图:

换个思路就是:要求返回1所在区间里面 0 的个数<= k 的大小,之后便是找子区间里面1的个数最

多 的问题 

解法一:暴力求解

 固定left  = 0,right = 0 ,count = 0

count 统计子数组里面0 的个数

解法二:滑动窗口

 每一轮结束后找到指定区间的时候,right 指针都需要在会去left  指向下一个元素的位置,但是新

一轮区间里面1的个数是小于或者等于上一轮[ left, right ] 指向区间里面1的个数,因为此时指向的

区间只是相较于上一轮指向区间减少1个元素,所以针对这个情况,可以使用“滑动窗口”的思想

2. 算法原理

分为4小步:

1)“进窗口”

nums[right++] == 0

count ++;

2)判断

if(count > k)

3)“出窗口”

if(nums[left] == 0 )

  count--;

4)结果更新

len = max(len,right -left);

3.  OJ代码
3.1 解法一代码
int longestOnes(vector<int>& nums, int k)
{
	int left = 0, right = 0, count = 0;//统计0 出现的次数
	int len = 0;
	for (; left < nums.size(); ++left)
	{
		right = left;
		for (; right < nums.size(); ++right)
		{
			if (nums[right] == 0)
				count++;
			//结果更新
			if (count > k)
			{
				len = max(len, right - left );
				count = 0;//重新归为0
				break;
			}
		}
	
	}
	return len;
}
3.2 解法二代码
  int longestOnes(vector<int>& nums, int k) 
    {
        int left = 0, right = 0, count = 0;//统计0 出现的次数
		int len = 0;
		while (right < nums.size())
		{
			if (nums[right] == 0)
				count++;
			right++;
			// if (count > k)
			// {
			// 	if (nums[left++] == 0)
			// 		count--;
			// }
            //对于这个代码可以进优化,可能存在非连续的0
           while(count > k)
			{
				if (nums[left++] == 0)
					count--;
			}
			len = max(len, right - left);
	
			
		}
		return len;

    }

三· 将x 减小到0的最小操作数

链接:将x 减小到0的最小操作数

 

 1. 题目分析

拿到此题目的时候,初始想法都是,遍历此数组,进行加和直至遍历所得的总和为 x 时候,返回此

时遍历元素的个数,即为题目所求。

图解分析:

2. 算法原理

其实换个思路就是:

找出一个最长的子数组的,同时这个子数组的所有元素之和恰好等于数组元素总和减去 x 

len: 最长子数组的长度

add: 最长子数组的所有元素之和 

sum : 数组所有元素之和

最小操作数:n - len 

n : 数组的原始大小

1)解法一:暴力求解

“双指针”思想:固定left = 0,right = 0,add = 0,len  = 0(记录最长子数组的元素个数)

对应时间 复杂度:O(N^2)

2)解法二:滑动窗口

还是一样的分析:每当add >= sum -x 的时候,right 都需要再次重新回到 left 所在元素的下一个位

置,再重新执行一样的操作,其实这个过程是没有必要的,此时只需要删除left 所指向的元素就

行,直至add <= sum -x.

3.  OJ代码

暴力求解代码:

int minOperations(vector<int>& nums, int x)
{
	//找出自由光最长子数组同时需要满足所有元素之和恰好为 sum - x
	int n = nums.size();
	if (x < nums[0] || x < nums[n - 1])
		return -1;//不存在
	int left = 0, right = 0, add = 0, sum = 0, len = 0;
	for (auto it : nums)
	{
		sum += it;
	}
    if(x > sum)
      return -1;
	for (; left < n; ++left)
	{
		for (right = left; right < n; right++)
		{
			add += nums[right];
			if (add > sum - x)
			{
				break;
			}
		  if (add == sum - x)
			{
				len = max(len, right - left + 1);
				break;
			}
			
		}
		add = 0;
	}
	return n - len;
}

滑动窗口代码:

int minOperations(vector<int>& nums, int x)
{
	//滑动窗口
	int n = nums.size();

	int sum = 0, add = 0, len = 0;
	for (auto it : nums)
		sum += it;
	if (x > sum)
		return -1;
	int left = 0, right = 0;
	while (right < n)
	{
		add += nums[right++];
		while (add > sum - x)
		{
			add -= nums[left++];
		}
		if (add == sum - x)
			len = max(len, right - left);
	}
	return len == 0 ? -1:n - len;
}

四.  找到字符串里面所有字母异位词

链接:找到字符串中所有字母异位词

 

1. 题目分析

常规思路:就是对s 这个字符串依次进行遍历,同时统计每一个有效字符出现的次数

对应的时间复杂度:O(N^2)

2. 算法原理

咱这里直接上“滑动窗口”的思想:

固定2个指针left = 0,right = 0;

定义2个数组 hash1[26] :用来存储p 这个字符串中每一个字符出现的次数

hash2[26]: 用来存储 s 这个字符串里面每隔 len  个字符里面有效字符出现的次数

len : p 这个字符串的大小

同时借助一个变量 flag :默认2数组里面的元素相同(便于后期在进行检查的时候,好判断)

 之所以把2个数组的大小固定为26:是因为题目中已经说明了:

3.OJ代码
vector<int> findAnagrams(string& s, string& p)
{
	//滑动窗口 + 2个数组(统计每一个字符出现的次数)
	int hash1[26] = { 0 };//统计p里面每一个字符出现的个数
	int hash2[26] = { 0 };//统计s里面每len个字符里面 每一个字符出现的个数
	int len = p.size();
	//统计p 里面每一个字符的个数
	int i = 0;
	while (i < len)
	{
		hash1[p[i] - 'a'] ++;//映射的思想
		i++;
	}

	int flag = 1;//标志位:默认2个字符数组相同

	int left = 0;
	int right = 0;
	vector<int> ret;
	while (right < s.size())
	{
		//进窗口
		hash2[s[right] - 'a']++;
		//判断&出窗口
		if ((right - left + 1) > len)
		{
			//窗口大小是固定的,所以只需要删除一个元素就可以
			hash2[s[left] - 'a']--;
			left++;
		}
		//更新结果
		if ((right - left + 1) == len)
		{
			int j = 0;
			i = 0;
			flag = 1;
			//while (n--)//注意不能判断len 次,是对全部数组进行判断
			while (i < 26)
			{
				if (hash1[i++] != hash2[j++])
				{
					flag = 0;
					break;
				}

			}
			if (flag == 1)
			{
				ret.push_back(left);
			}
		}
		right++;

	}
    // 出了循环,还需要在进判断依次是否,满足一个有效的区间
	if ((right - left + 1) == len)
	{
		int j = 0;
		i = 0;
		flag = 1;
		//while (n--)//注意不能判断len 次,是对全部数组进行判断
		while (i < 26)
		{
			if (hash1[i++] != hash2[j++])
			{
				flag = 0;
				break;
			}

		}
		if (flag == 1)
		{
			ret.push_back(left);
		}
	}
	return ret;
}

 其实对于这个代码还是有优化的空间的。

此代码的时间复杂度是:O(N),准确的说是O(26N)

在进行结果更新的时候,可以采用一个Count 计数的方法

Count:记录子数组里面的有效字符的个数,这样就可以减少判断的次数。

需要在进窗口,出窗口,以及结果更新的时候,都需要对Count 进行维护。

注意Count 含义: 记录的是有效字符的个数

进窗口:

判断当前 right 所指向的元素在 hash2这个数组里面的指定位置出现的次数是否 <= hash1

这个数组里面指定位置出现的次数。若是满足count++

出窗口:

对left 指向的元素进行删除,注意Count-- 的条件

只有当 left 指向的字符出现的次数  <=  在p 这个字符串里面出现的次数,才可以Count --

结果更新:

当Count == len 的时候,left  所指向的元素就是一个有效的位置。

vector<int> findAnagrams(string& s, string& p)
{
	//采用Count记录有效字符出现的个数
	int count = 0;
	int hash1[26] = { 0 };
	int hash2[26] = { 0 };
	int len = p.size();
	//统计p 字符串里面每一个字符出现 次数
	for (auto it : p)
		hash1[it - 'a']++;
	int right = 0, left = 0;
	vector<int>ret;
	while (right < s.size())
	{
		//进窗口
		char in = s[right];
		if (hash2[in - 'a']++ < hash1[in - 'a'])
			count++;
		//出窗口
		if (right - left+1 > len)
		{
			char out = s[left++];
			if (hash2[out - 'a']-- <= hash1[out - 'a'])
				count--;

		}
		//结果更新
		if (count == len)
			ret.push_back(left);
		right++;
	}
	return ret;
}

结语:

以上就是关于“滑动窗口”部分应用的OJ题目,对于这一思想的掌握,需要我们在暴力算法思想的基础之上进行优化,所以“暴力求解”是我们进入“滑动窗口”世界之门的一把“钥匙”,对于滑动窗

口的掌握,无非就是分4个小步骤:

1)进窗口

2)判断

3)出窗口

4)结果更新

可能结果更新这一步骤,不一定就是在“出窗口”之后,也可能在前面或者同时进行。总之,刷算法

题,画图结合思想是必不可少的,希望各位看到此篇博客,对于“滑动窗口”这一思想的理解和掌

握,可以有所帮助。

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

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

相关文章

24/9/19 算法笔记 kaggle BankChurn数据分类

题目是要预测银行里什么样的客户会流失&#xff0c;流失的概率是多少 我这边先展示一下我写的二分类的算法 import numpy as np import pandas as pd import matplotlib.pyplot as plt from sklearn.model_selection import train_test_split from sklearn.linear_model impo…

亚马逊IP关联揭秘:发生ip关联如何处理

在亚马逊这一全球领先的电商平台上&#xff0c;IP关联是一个不可忽视的问题&#xff0c;尤其是对于多账号运营的卖家而言。本文将深入解析亚马逊IP关联的含义、影响以及应对策略&#xff0c;帮助卖家更好地理解和应对这一问题。 什么是亚马逊IP关联&#xff1f; 亚马逊IP关联…

awk从0学习

1. 入门 1.1 什么是 awk&#xff1f; ①Awk是一种文本处理工具&#xff0c;适用于处理结构化数据&#xff0c;例如表格数据。 ②它可以读取一个或多个文本文件&#xff0c;并执行模式扫描和处理等指定的操作。 ③基本逻辑涉及数据的提取&#xff0c;排序和计算。 ④支持复…

Leetcode 2464. 有效分割中的最少子数组数目

1.题目基本信息 1.1.题目描述 给定一个整数数组 nums。 如果要将整数数组 nums 拆分为 子数组 后是 有效的&#xff0c;则必须满足: 每个子数组的第一个和最后一个元素的最大公约数 大于 1&#xff0c;且 nums 的每个元素只属于一个子数组。 返回 nums 的 有效 子数组拆分中…

Lumos学习王佩丰Excel第十五讲:条件格式与公式

一、使用简单的条件格式 1、为特定范围的数值标记特殊颜色 条件格式-需选择设定范围&#xff08;大于/小于/介于/......&#xff09;&#xff1a; 数值会动态根据条件判断更新颜色&#xff1a; 模糊匹配&#xff0b;条件格式&#xff1a;选择包含部分文本的特殊值 2、查找重复…

linux-----进程控制

提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、fork()函数 返回值&#xff1a;子进程返回0&#xff0c;父进程返回子进程的id,出错就返回-1. fork创建子进程&#xff0c;如果父子一方发生写入时&#xff0c;就会发生写实拷贝&#xff0c;操作系统就…

专业学习|动态规划(概念、模型特征、解题步骤及例题)

一、引言 &#xff08;一&#xff09;从斐波那契数列引入自底向上算法 &#xff08;1&#xff09;知识讲解 &#xff08;2&#xff09;matlap实现递归 &#xff08;3&#xff09;带有备忘录的遗传算法 &#xff08;4&#xff09;matlap实现带有备忘录的递归算法 “&#xff1…

0基础跟德姆(dom)一起学AI 数据处理和统计分析06-数据组合和缺失值处理

* 数据组合 * concat * merge * join(了解) * 缺失值处理 * apply方法详解 --- 1.DataFrame数据组合-concat连接 * 概述 * 连接是指把某行或某列追加到数据中, 数据被分成了多份可以使用连接把数据拼接起来 * 把计算的结果追加到现有数据集&#xff0c;也可以使用连…

Redis:常用命令总结

目录 1 . 前置内容 1.1 基本全局命令 KEYS EXISTS DEL EXPIRE TTL TYPE 1.2 数据结构和内部编码 2. String类型 SET GET MGET MSET INCR INCRBY DECR DECRBY INCRBYFLOAT 命令小结​编辑 内部编码 3 . Hash 哈希类型 HSET HGET HEXISTS HDEL HKEYS …

Qemu开发ARM篇-5、buildroot制作根文件系统并在qemu中进行挂载启动

文章目录 1、 buildroot源码获取2、buildroot配置3、buildroot编译4、挂载根文件系统 在上一篇 Qemu开发ARM篇-4、kernel交叉编译运行演示中&#xff0c;我们编译了kernel&#xff0c;并在qemu上进行了运行&#xff0c;但到最后&#xff0c;在挂载根文件系统时候&#xff0c;挂…

嵌入式单片机STM32开发板详细制作过程--01

大家好,今天主要给大家分享一下,单片机开发板的制作过程,原理图的制作与PCB设计,以及电子元器件采购与焊接。 第一:单片机开发板成品展示 板子正面都有各个芯片的丝印与标号,方便焊接元器件的时候,可以参考。(焊接完成之后,成品图如下) 第二:开发板原理图制作 在制…

OpenCV系列教程三:形态学、图像轮廓、直方图

文章目录 一、形态学1.1 阈值处理1.1.1 全局阈值处理1.1.2 全局阈值处理之Otsus 阈值法1.1.3 自适应阈值处理 1.2 腐蚀与膨胀1.2.1 腐蚀操作1.2.2 创建形态学卷积核1.2.3 膨胀操作 1.3 开运算和闭运算1.4 形态学梯度1.5 顶帽操作(tophat)1.6 黑帽操作&#xff08;Black Hat&…

基于JAVA+SpringBoot+Vue的社区智慧养老监护管理平台

基于JAVASpringBootVue的社区智慧养老监护管理平台 前言 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN[新星计划]导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末附源码下载链接&#x1…

Arthas heapdump(dump java heap, 类似 jmap 命令的 heap dump 功能)

文章目录 二、命令列表2.1 jvm相关命令### 2.1.8 heapdump&#xff08;dump java heap, 类似 jmap 命令的 heap dump 功能&#xff09;举例1&#xff1a;假设你想生成一个只包含活动对象的堆转储文件&#xff0c;并将其保存为 /tmp/heapdump.hprof举例2&#xff1a;如果你想要进…

社区团购的创新与变革——融合开源链动 2+1 模式、AI 智能名片及 S2B2C 商城小程序

摘要&#xff1a;本文从信息流、资金流、物流角度深入分析社区团购的特点&#xff0c;探讨其如何避免传统线下中心零售的高展示成本与传统电商的高交付成本。同时&#xff0c;引入开源链动 21 模式、AI 智能名片及 S2B2C 商城小程序等创新元素&#xff0c;阐述它们为社区团购带…

MySQL---创建数据库(基于SQLyog)

目录 0.前言 1.基本认识 1.1编码集 1.2检验规则 2.库的创建和销毁 2.1指令介绍 2.2你可能会出现的问题 3.查看数据库属性 4.创建指定数据库 5.创建表操作 0.前言 之前写过一篇这个关于表的创建和销毁的操作&#xff0c;但是当时是第一次学习&#xff0c;肯定有些地方…

华为OD机试 - N个选手比赛前三名、比赛(Java 2024 E卷 100分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;E卷D卷A卷B卷C卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加…

【STM32】TIM定时器定时中断与定时器外部时钟的使用

TIM定时器定时中断与定时器外部时钟的使用 一、TIM定时器简介1、TIM&#xff08;Timer&#xff09;定时器2、定时器类型3、高级定时器4、通用定时器5、基本定时器6、定时中断基本结构代码编写&#xff1a;定时中断/外部时钟定时中断 7、预分频器时序8、计数器时序9、计数器无预…

手写SpringMVC

1、开发HspDispatcherServlet 2、完成客户端/浏览器可以请求控制层 目的&#xff1a;发出url请求时&#xff0c;经过前端控制器&#xff0c;找到Monster的List方法&#xff0c;把结果再打回去 3、从web.xml动态获取hspspringmvc.xml 4、完成自定义Service注解功能 目的&…

【功能详解】IoTDB 与 ThingsBoard 成功集成!

可视化工具集成1 IoTDB 实现了 ThingsBoard 的无缝集成对接&#xff0c;IoTDB 构建的工业数据存储处理-可视化呈现链路又多了一种可用、易用的工具选择。 我们的代码已贡献到 ThingsBoard 社区&#xff08;待发版&#xff09;&#xff0c;用户手册也已发布&#xff08;可点击下…