【算法笔记】双指针及其经典例题解析

1.双指针定义

双指针时候又叫做尺取法或者滑动窗口,我们一般定义两个指针一个左指针left, 一个右指针right当条件满足时根据左右区间更新结果

有时候我们会发现不一定需要套两层for循环才能得出结果,如果使用双指针的话且指针不用回退那我们就可以使用双指针法,将我们时间复杂度由O(n ^ 2)优化为了O(n)


2.双指针经典例题

2.1唯一的雪花 Unique Snowflakes

这道题是我们双指针的模板题,我们可以首先创建一个哈希表用来保持这个元素出现的次数,当我们的右指针遍历到时,让这个元素进窗口也就是利用哈希表记录这个元素出现的次数加一,当这个区间不合法时(出现重复元素)让左指针向右指针的方向移动,左指针移动时会让左指针移动前指向的那个元素在这个区间出现的次数减一,当窗口变成重新合法时我们就更新结果,对这些结果取一个最大值即可:

cpp 复制代码
#include <iostream>
#include <unordered_map>
using namespace std;

const int N = 1e6 + 10;
int a[N];

int main()
{
	int T; cin >> T;
	while (T--)
	{
		int n; cin >> n;
		for (int i = 1; i <= n; i++) cin >> a[i];
		//初始化
		int left = 1, right = 1, ret = 0;
		unordered_map<int, int> mp;
		while (right <= n)
		{
			//记录次数 
			mp[a[right]]++;
			//判断并回到合法窗口 
			while (mp[a[right]] > 1)
			{
				mp[a[left]]--;
				left++;
			}
			ret = max(ret, right - left + 1);
			right++;
		}
		cout << ret << endl;
	}
}

2.2逛画展

其实用双指针来解决的题模板都差不多,主要是体现在进窗口和出窗口已经更新方式的不同,其余的地方还是比较的相似的

这道题的目标是在尽可能小的区间内看过所有的画,所以我们可以定义一个变量cnt用于记录这个区间内有几个画家,很明显这道题是允许区间内有重复的元素的,所以我们假设哈希表为mp,这个值为x的话,当mp[x]冲零变一时就是区间内有新画家的画,让cnt++,当cnt满足时更新一下结果当mp[x]从一变零时代表区间内少了一位画家的画,最后我们取最小的区间大小就可以了:

cpp 复制代码
#include <iostream>
#include <unordered_map>
using namespace std;
const int N = 1e6 + 10;
int a[N];
int n, m;

int main()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++) cin >> a[i];
	unordered_map<int, int> mp;
	int left = 1, right = 1;
	int cnt = 0, begin = 1; 
	int ret = n;
	while (right <= n)
	{
		if (mp[a[right]] == 0) cnt++;
		mp[a[right]]++;
		while (cnt == m)
		{
			int len = right - left + 1;
			if (len < ret)
			{
				ret = len;
				begin = left;	
			}
			if (mp[a[left]]-- == 1) cnt--;
			left++;
		}
		right++;
	}
	cout << begin << ' ' << begin + ret - 1 << endl;
	return 0;
}

2.3字符串

这道题和上一题几乎一摸一样就是换了一个条件而已了,所以这里就直接贴代码了

cpp 复制代码
#include <iostream>
#include <unordered_map>
using namespace std;
const int N = 1e6 + 10;
string s1;
unordered_map<char, int> mp;
int king;

int main()
{
	cin >> s1;
	int n = s1.size();
	int left = 0, right = 0, ret = 0x3f3f3f3f;
	while (right < n)
	{
		if (mp[s1[right]]++ == 0) king++;
		while (king == 26)
		{
			ret = min(ret, right - left + 1);
			if(mp[s1[left]]-- == 1) king--;
			left++;
		}
		right++;
	}
	cout << ret << endl;
	return 0;
}

2.4丢手绢

根据题目的条件我们可以这道小朋友之间的距离是小于总距离和sum / 2的,所以当两个小朋友的距离不合法时出窗口并更新结果在结果里取最大值即可

cpp 复制代码
#include <iostream>
using namespace std;

const int N = 1e5 + 10;
typedef long long LL;
int n;
LL a[N];

int main()
{
	LL sum = 0; cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
		sum += a[i];
	}
	int left = 1, right = 1;
	LL k = 0;
	LL ret = 0;
	while (right <= n)
	{
		k += a[right];
		while (2 * k >= sum)
		{
			ret = max(ret, sum - k);
			k -= a[left++];
		}
		ret = max(ret, k);
		right++;
	}
	cout << ret << endl;
	return 0;
}

相关推荐
黎阳之光1 小时前
黎阳之光:以视频孪生+全域感知,助力低空经济破局突围
大数据·人工智能·算法·安全·数字孪生
CM莫问2 小时前
详解机器学习中的马尔可夫链
人工智能·算法·机器学习·概率论·马尔可夫·马尔科夫
南宫萧幕2 小时前
基于 Luenberger 观测器的 PMSM 无速度传感器 id=0 矢量控制系统 Simulink 建模与实现(一)
算法·matlab·汽车·控制
斯维赤2 小时前
每天学习一个小算法:选择排序
java·学习·算法
超级码力6662 小时前
【Latex第三方文档类standalone】standalone类介绍及应用
算法·数学建模·信息可视化
明朝百晓生2 小时前
强化学习 [chapter10] [page3 ]Actor-Critic Methods
算法
peterfei2 小时前
一个 Tauri + Rust AI 编辑器是怎么同时适配 5 家 AI 大厂的?IfAI v0.4.3 架构拆解
人工智能·算法·架构
Via_Neo2 小时前
桶排序算法
算法·排序算法
China_Yanhy3 小时前
生产笔记:AI 集群的极致成本与数据保命指南
人工智能·笔记