春招Leetcode刷题日记-D4-双指针算法-滑动窗口快慢指针

news2024/12/28 4:50:02

D4-双指针算法-滑动窗口&&快慢指针

  • 快慢指针算
    • 力扣141. 环形链表
      • 思路
      • 代码
    • 力扣142. 环形链表 II
      • 思路
      • 代码
  • 滑动窗口
    • 力扣76. 最小覆盖子串
      • 思路
      • 代码
    • 力扣424. 替换后的最长重复字符
      • 思路
      • 代码


快慢指针算

快慢指针算法,多用于链表当中,常见的如:快慢指针判断链表中是否含有环路&&快慢指针找链表中点问题

力扣141. 环形链表

题目链接:141. 环形链表
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

思路

这是非常经典的,Floyd判圈法,即利用快慢指针,判断链表中是否含有环路。

1、初始时,slow、fast都在开头节点
2、fast一次走两步,slow一次走一步
3、如果含有环路,二者一定在环路中相遇;反之fast先走到尾节点

代码

class Solution {
public:
	bool hasCycle(ListNode *head) {
		ListNode *slow = head, *fast = head;
		while (fast != nullptr&&fast->next != nullptr) {//快慢指针判断条件!!!
			slow = slow->next;
			fast = fast->next->next;
			if (slow == fast) {
				return true;
			}
		}
		return false;
	}
};

力扣142. 环形链表 II

题目链接:142. 环形链表 II
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

思路

本题为上一题的进阶版本,我们不仅要判断是否含有环路,还要判断环路的进入节点,并返回。
1、所以,我们第一步就是利用快慢指针,利用是否会有第一次相遇,判断出是否含有环路,思路同上一题。
2、当相遇时,二者处在环路中某一个节点,现在我们要通过分析快慢指针走过的步数,来进一步指定算法

1、设非环路部分链表共a个节点,环路部分链表共b个节点(a,b均未知,具体要看题目)
2、我们从头部出发,到达环路入口节点:要么直接走过去,即a步;要么走入环路,在环路中绕行整数个圈到达。综上,总步数为 a+nb(n为绕行圈数,为未知,看具体链表)
3、再来分析快慢指针已经走了多少步:分别设为f、s步
<1>f=2
s(快指针一次两步,慢指针一次一步)
<2>f=s+nb(快慢指针都同样走过了a步,快指针多比慢指针在环路中走了几圈,且n为未知)
所以f=2nb、s=nb
4、在当下,慢指针已经走了n
b步,根据上面分析,再走a步就是目标节点。但是,现在a是未知,根据上面分析,我直接从起点走a步也会到目标点。
5、综上,让快指针去链表头,让快慢指针同时按照一个速度出发,二者相遇的时候,同时走了a步,即为目标点

代码

class Solution {
public:
	ListNode *detectCycle(ListNode *head) {
		ListNode *slow = head, *fast = head;
		while (fast != nullptr&&fast->next != nullptr) {//快慢指针判断条件
			slow = slow->next;
			fast = fast->next->next;
			if (slow == fast) {//产生第一次相遇,证明含有环路,开始寻找目标点
				fast = head;//这里算法详见上面证明
				while (fast != slow) {
					fast = fast->next;
					slow = slow->next;
				}
				return slow;
			}
		}
		return nullptr;//不产生第一次相遇,不含有环路
	}
};

滑动窗口

1、滑动窗口,又名双指针法,左右两个指针(l,r),同方向且l<=r,用于区间搜索。
2、只要分析出滑动窗口法之后,马上想到滑窗固定大板子:

1、滑窗之中,一定要重点统计窗口内部数据情况,这个和窗口是否收缩有很大关系
2、总体思路就是,先进行右边界扩张,更新窗口内数据信息;再根据题意判断,是否左边界++,进行窗口收缩,收缩的话,一定注意更新窗口内数据信息
3、左右指针初始化为 0 -1

	int left = 0, right = -1;
 	for (遍历一遍数组) {
		// c 是将移入窗口的字符
   	 	char c = s[right];
    	// 右移窗口
    	right++;
    	// 进行窗口内数据的一系列更新
    	...   
    	// 判断左侧窗口是否要收缩
    	while (左指针需要移动,即窗口需要收缩) {
        	// d 是将移出窗口的字符
        	char d = s[left];
        	// 左移窗口
        	left++;
        	// 进行窗口内数据的一系列更新
        	...
    	}

力扣76. 最小覆盖子串

题目链接:76. 最小覆盖子串
在这里插入图片描述
在这里插入图片描述

思路

本题要求我们在s中找一个片段,这个片段中必须包含t中全部出现的字母,即t中出现了2个a,那么目标片段必须出现2个a,且要求在所有满足要求的片段之中找到最短的(根据题意,答案一定唯一),这明显是区间搜索问题,马上想到滑窗法,立刻开始套模板

1、初始化 l=0,r=-1,针对滑窗,我们要统计滑窗内各个元素出现的个数,针对t,我们要统计出现了哪些元素,以及出现的次数。
2、每次先右边界++,扩充滑窗,更新滑窗内元素。
3、最重要的地方来了,如何判断是否缩小滑窗(即左边界++):如果当前滑窗内都为覆盖到所有目标元素,那么缩小滑窗之后,更是不可能覆盖。所以只有当扩充玩新元素后全覆盖到了,才考虑缩小滑窗。
4、为了看是否能达到覆盖,用sum记录还需要覆盖的字母总量,用tmp数组动态维护需要覆盖的各个字母剩余数量。
5、根据题意,当能覆盖之后,我们要这个片段尽可能的短,所以在缩小滑窗时候,当恰好排出这个元素之后,无法完全覆盖,这就代表着不缩小时,就是当前的满足要求的最短片段。所以,我们连续缩小滑窗,直到上述情况出现即可。为了让最终结果最小,要动态维护一个最短片段。

在这里插入图片描述

代码

注意:
1、字符串裁剪函数substr使用方式:
假设:string s = “0123456789”;
string sub1 = s.substr(5); //只有一个数字5表示从下标为5开始一直到结尾:sub1 = “56789”
string sub2 = s.substr(5, 3); //从下标为5开始截取长度为3位:sub2 = “567”
2、比如t串中只出现两个a,但窗口内出现了三个a,只有前两个算有效覆盖(既在t中出现,又满足出现次数),所以tmp就是用来动态维护这个事情

class Solution {
public:
	string minWindow(string s, string t) {
		int m = s.size(), n = t.size();
		//统计字符串t里面的字符信息
		vector<int> cnt1(128, 0);//统计t中各个字母出现的次数
		vector<bool> visit1(128, false);//看t中出现了哪些字母
		for (int i = 0; i < n; i++) {
			cnt1[t[i]]++;
			visit1[t[i]] = true;
		}
		
		//用来动态记录最短符合要求字串
		int min_l = -1, min_r = -1, mins = 1000001;//左边界,右边界,长度
		
		int l = 0, r = -1;//窗口左右指针
		int sum = n;//还未覆盖到的字母总数
		vector<int> tmp(cnt1);//复制一下cnt1,动态维护一下窗口内还需要覆盖的各个字母的个数
		vector<int> cnt2(128, 0);//维护窗口内所有元素出现的次数
		
		for (int i = 0; i < m; i++) {
			char tar = s[i];//待扩充进来的字符
			r++;//扩充右边界
			cnt2[tar]++;//更新窗口内元素出现次数
			//扩充进来的字母是有效的覆盖,解释看上面的注意部分
			if (visit1[tar] == true && tmp[tar] != 0) {
				sum--;//要覆盖的总数-1
				tmp[tar]--;//窗口内该字母还需要出现的次数-1
			}
			//开始判断是否要缩减窗口
			if (sum == 0) {//刚刚好,窗口扩展到全覆盖时候,才开始动左指针,找到当前状态下最小
				//当前窗口完全可以覆盖,为了找最小,我们收缩左边界,直到恰好覆盖(即再缩就不可以覆盖为止)
				//这时候,就是当前状态下最小
				while (sum == 0) {//连续缩小
					char tar2 = s[l];//待排除的元素
					if (visit1[tar2] == true) {//被扔出去的字母是有效字母,反之直接扔即可(l++)
						cnt2[tar2]--;//动态维护窗口内各字母个数,有效字母被扔出去后,它的新数量
						if (cnt2[tar2] < cnt1[tar2]) {//当前窗口不能恰好覆盖目标字母,这个时候就是连续缩窗口的尽头,开始更新动态维护的数据
							sum++;//窗口内待覆盖的元素+1
							if (r - l + 1 < mins) {//动态维护最小子串
								mins = r - l + 1;
								min_l = l;
								min_r = r;
							}
							tmp[tar2]++;//该字母在窗口内还需出现的次数+1
							l++;//缩窗口
							break;//退出连续缩窗口
						}
					}
					l++;
				}
			}
		}
		return min_l == -1 ? "" : s.substr(min_l, min_r-min_l+1);//始终未找到合适的窗口,min_l==-1,返回空串;反之按照大小裁剪目标串s
	}
};

力扣424. 替换后的最长重复字符

题目链接424. 替换后的最长重复字符
在这里插入图片描述

思路

明显的,在大区间中,找一个连续的小区间,经过不多于k次的变化之后,让其中元素都统一,且这个片段要最长。区间搜索,马上想滑窗,上模板:

1、初始化 l=0 ;r=-1 ;统计窗口内各个元素个数;一个窗口内,为了在有限的替换之后,整体最长,肯定是维护一个个数最多的元素,把和他不同的全换下去,这样才会最长,也能最大程度上利用k,所以维护窗口内最大元素个数
2、r++,扩充窗口,更新元素数量,因为该字母变多了,可能成为最多的个数,所以也要维护窗口内最大元素个数
3、滑窗问题关键来了,缩小窗口:当”非最多数量元素“个数小于等于k(可替换数量),说明这次扩充是可以的,窗口确实可以扩张,不需要收缩(因为题目要的就是最长),反之,就得收缩,更新的数据同上

代码

class Solution {
public:
	int characterReplacement(string s, int k) {
		int n = s.size();
		vector<int> cnt(26, 0);//窗口各个字母个数
		int l = 0, r = -1;
		int maxs = 0;
		for (int i = 0; i < n; i++) {
			char tar = s[i];//待扩充元素
			r++;//扩充
			cnt[tar - 'A']++;//两次更新数据
			maxs = max(maxs, cnt[tar - 'A']);
			if (r - l + 1 - maxs > k) {//扩充失败了,必须要收缩一下
				char tmp = s[l];
				cnt[tmp - 'A']--;
				for (int j = 0; j < 26; j++) {
					maxs = max(maxs, cnt[j]);
				}
				l++;
			}
		}
		return r - l + 1;
	}
};

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

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

相关文章

Java锁相关知识

目录 线程安全 对象头Mark 偏向锁 轻量级锁 减少锁持有时间 减小锁粒度 锁分离 锁粗化 锁消除 无锁自旋锁 线程安全 多线程访问ArrayList 多线程网站统计访问人数,是否需要精确统计&#xff1f;如果不需要&#xff0c;可以不进行加锁 public static List<Integ…

ROS2 humble安装-chatgpt版本

如果按照chatgpt版本可能不合适。请一定要参考官网。ROS (Robot Operating System) 是一个开源的机器人操作系统&#xff0c;提供了一系列软件库和工具&#xff0c;用于构建机器人应用程序。以下是在 Ubuntu 系统中安装 ROS Humble 的详细步骤和方法&#xff1a;首先&#xff0…

网络安全入门必备:渗透常用命令速查手册

系统信息 arch #显示机器的处理器架构(1) uname -m #显示机器的处理器架构(2) uname -r #显示正在使用的内核版本 dmidecode -q #显示硬件系统部件 - (SMBIOS / DMI) hdparm -i /dev/hda #罗列一个磁盘的架构特性 hdparm -tT /dev/sda #在磁盘…

CMake系列:正确使用多配置编译系统

目录 常见错误 问题现象 正确做法 if指令应该什么时候使用 活学活用 把IF指令用于多配置编译系统是很多初学者容易犯下的错误。这篇文章启示性的教你如何正确理解、使用CMake的多配置编译系统。 常见错误 以Debug和Release配置有不同的宏定义为例&#xff0c;如下所示&a…

大数据选股智能推荐系统V1.0-1

很长时间没有发布博客了&#xff0c;这段时间个人确实有点忙。另外一方面在这段时间我也没有闲着。自己研发了一套大数据选股的智能推荐系统。废话不说&#xff0c;我们先来看这套系统&#xff1a;登录页面&#xff1a;&#xff08;技术点&#xff1a;验证码的生成&#xff09;…

webrtc QOS笔记一 Neteq直方图算法浅读

webrtc QOS笔记一 Neteq直方图算法浅读 文章目录webrtc QOS笔记一 Neteq直方图算法浅读Histogram Algorithm获取目标延迟遗忘因子曲线Histogram Algorithm DelayManager::Update()->Histogram::Add() 会根据计算的iat_packet(inter arrival times, 实际包间间隔 / 打包时长…

基于SpringBoot的在线课程管理系统

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7/8.0 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.3.9 浏…

哈尔滨工业大学2020届面向服务复习笔记

目录 一、面向服务架构SOA 1.SOA概念 SOA所解决的问题 SOA的特性 SOA的特征 SOA组成要素 2.SOA服务设计原则 3.SOA协作模式 4.SOMA开发方法 SOMA生命周期 敏捷开发 服务外包与众包 5.ESB原理与机制 ESB解决的问题 ESB的功能 ESB关键技术 ESB的优势 6.服务组…

【Opencv--形态学操作】膨胀、腐蚀、开/闭操作:cv2.morphologyEx、cv2.erode、cv2.dilate

【Opencv–形态学操作】膨胀、腐蚀、开/闭操作 文章目录【Opencv--形态学操作】膨胀、腐蚀、开/闭操作1. 介绍2. 形态学操作2.1 腐蚀和膨胀2.1.1 腐蚀2.1.2 膨胀2.1.3 代码示例2.2 开/闭操作2.2.1 开操作2.2.2 闭操作2.2.3 代码示例2.3 礼帽和黑帽2.3.1 礼帽运算2.3.2 黑帽运算…

恭喜! SelectDB 五位开发者成为 Apache Doris 新晋 PMC 成员和 Committer!

近期&#xff0c;通过 Apache Doris 项目管理委员会的推荐与投票&#xff0c;Apache Doris 社区正式迎来了 2 位新晋 PMC 成员 和 8 位新晋 Committer 的加入。值得关注的是&#xff0c;2 位新晋 PMC 成员均来自 SelectDB&#xff0c;分别是衣国垒&#xff08;yiguolei&#xf…

【蓝桥杯集训4】双指针专题(6 / 6)

目录 3768. 字符串删减 - 滑动窗口ac 799. 最长连续不重复子序列 - 滑动窗口 800. 数组元素的目标和 - 二分ac 2816. 判断子序列 - 双指针 1238. 日志统计 - 滑动窗口 1240. 完全二叉树的权值 - 双指针 1、前缀和 - 通过了 5/12个数据 2、双指针 3768. 字符串删减 -…

<<Java开发环境配置>>6-SQLyog安装教程

一.SQLyog简介: SQLyog 是一个快速而简洁的图形化管理MySQL数据库的工具&#xff0c;它能够在任何地点有效地管理你的数据库&#xff0c;由业界著名的Webyog公司出品。使用SQLyog可以快速直观地让您从世界的任何角落通过网络来维护远端的MySQL数据库。 二.SQLyog下载: 下载地址…

mySQL服务主从实现

一主一从1.1 环境准备&#xff1a;centos系统服务器2台、 一台用户做Mysql主服务器&#xff0c; 一台用于做Mysql从服务器&#xff0c; 配置好yum源、 防火墙关闭、 各节点时钟服务同步、 各节点之间可以通过主机名互相通信1.2 准备步骤&#xff1a;1&#xff09;iptables -F &…

多态和可变参数

多态 多态是同一个行为具有不同的表现形式或者形态的能力 &#x1f47f;多态的作用:主要用来实现动态性,提高程序的灵活性和扩展性 &#x1f916;故事:大宝-小宝是父子,有一天小宝接到打给大宝的电话,让大宝去喝喜酒,但是大宝不在家,小宝急中生智想到假扮成大宝去参加喜宴,这个…

Unity法线贴图原理理解(为什么存在切线空间?存的值是什么?)

Unity法线贴图原理理解(为什么存在切线空间&#xff1f;存的值是什么&#xff1f;&#xff09;写在前面1、为什么用法线贴图&#xff1f;2、用什么存法线&#xff1f;3、法线向量为什么存在切线空间&#xff1f;法线贴图存得是什么&#xff1f;4、法线贴图为什么会偏蓝&#xf…

MySQL字段值如何区分大小写

MySQL字段值如何区分大小写 注意&#xff1a;设置的是字段值区分大小写 1. 查询时指定大小写敏感&#xff0c;加关键字‘BINARY’ &#xff08;1&#xff09;删表&#xff0c;建表&#xff0c;新增数据 drop table binary_test; CREATE TABLE binary_test (id INT unsigned P…

2023年浙江建筑施工物料提升(建筑特种作业)模拟试题及答案

百分百题库提供特种工&#xff08;物料提升机&#xff09;考试试题、特种工&#xff08;物料提升机&#xff09;考试预测题、特种工&#xff08;物料提升机&#xff09;考试真题、特种工&#xff08;物料提升机&#xff09;证考试题库等,提供在线做题刷题&#xff0c;在线模拟考…

Zebec完成BNB Chain以及Near链上协议部署,多链化进程加速

从去年开始&#xff0c;Zebec 就开始以多链的形式来拓展自身的流支付生态&#xff0c;一方面向更多的区块链系统拓展自身流支付协议&#xff0c;即从Solana上向EVM链上对协议与通证等进行迁移与拓展。目前基本完成了在BNB Chain以及Near上的合约部署&#xff0c;且能够在这些EV…

handler解析(4)-Message及Message回收机制

Message中可以携带的信息 Message中可以携带的数据比较丰富&#xff0c;下面对一些常用的数据进行了分析。 /*** 用户定义的消息代码&#xff0c;以便当接受到消息是关于什么的。其中每个Hanler都有自己的命名控件&#xff0c;不用担心会冲突*/ public int what; /*** 如果你…

Mrkdown相关快捷键

Mrkdown相关快捷键欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚…