洛谷P1638 逛画展

思路

 用双指针找出符合题意的区间。然后左指针右移,区间更新,若新区间不符题意,则右指针右移,直到区间符合题意。再左指针右移......循环往复,即可找出所有符合题意的区间,再找出最优区间即可。

代码

#include<iostream>
#include<vector>
#include<limits.h>
using namespace std;
int sum;//统计区间不同数字的个数
int ans = INT_MAX;
int main()
{
	int n,t;
	cin >> n >> t;
	vector<int> a(n+5,0);//区间开大一点,后面会解释
	vector<int> b(t+1,0);
	int l = 1, r = 1;
	//从1开始,避免处理下标0
	int L = 0, R = 0;//记录双指针的位置
	for (int i = 1; i <= n ;i++) cin >> a[i];
	while (l <= r && r <= n + 1)//这里r <= n + 1有等于的原因会在下面“坑”里讲
	{
		if (sum < t)
		{
			r++;
			b[a[r-1]]++;
			//双指针一般是[l,r),所以先r++
			if (b[a[r-1]] == 1) sum++;//若该数字区间内第一次出现,统计
		}
		//如果区间不符题意,右指针右移
		else
		{
			if (r - l < ans)
			{
				ans = r - l;
				R = r - 1;
				L = l;
			}
			//记录最优区间的左右端点
			b[a[l]]--;
			if (b[a[l]] == 0) sum--;
			//若区间不符题意,sum--,右指针移动
			l++;
			//左指针右移,若区间符合题意,左指针继续右移
		}
	}
	cout << L << " " << R;
	return 0;
}

坑!!!(右端点的问题)

5  5

1,2,3,4,5 

如果出现这样的数据,右指针不断右移。当r=6时,循环后sum==5,r=7,然后进入下一循环,因为r=7,循环终止。所以就统计不了L,R的数据。因此执行后结果会是0,0

感谢阅读~

### 包含所有名师作品的最小区间问题 要找到一个包含所有 `m` 位名师绘画的最小区间,可以使用 **双指针(滑动窗口)** 算法。该算法通过维护一个窗口 `[left, right]` 来动态调整区间范围,从而在时间复杂度为 O(n) 的情况下解决问题。此方法的核心思想是通过两个指针的移动来扩展和收缩窗口,以找到满足条件的最小长度区间。 #### 算法步骤 - 使用两个指针 `left` 和 `right` 来表示窗口的左右边界。 - 使用一个哈希表 `count` 来记录当前窗口中每个画家绘画的数量。 - 使用一个计数器 `unique` 来统计当前窗口中包含的不同画家的数量。 - 当窗口中包含所有 `m` 位画家的绘画时,尝试缩小窗口的左边界以寻找更短的满足条件的区间。 - 在整个过程中,不断更新最小窗口的起始和结束位置。 #### C++ 实现代码 ```cpp #include <iostream> #include <vector> #include <unordered_map> #include <climits> using namespace std; int main() { int n, m; cin >> n >> m; vector<int> paintings(n); for (int i = 0; i < n; ++i) { cin >> paintings[i]; } unordered_map<int, int> count; int left = 0, right = 0, unique = 0; int minLen = INT_MAX, minLeft = 0, minRight = 0; while (right < n) { if (count[paintings[right]] == 0) { unique++; } count[paintings[right]]++; while (unique == m) { if (right - left + 1 < minLen) { minLen = right - left + 1; minLeft = left; minRight = right; } count[paintings[left]]--; if (count[paintings[left]] == 0) { unique--; } left++; } right++; } cout << minLeft + 1 << " " << minRight + 1 << endl; return 0; } ``` #### 关键点说明 - 初始状态下窗口为空,通过右指针不断向右扩展,将当前元素加入哈希表并更新不同画家数量的计数器。 - 当窗口包含所有 `m` 位画家绘画时,进入内层循环,尝试移动左指针以缩小窗口。 - 每次窗口满足条件时,更新最小窗口长度及对应的起始和结束位置。 - 最终输出的 `minLeft + 1` 和 `minRight + 1` 是题目要求的从 1 开始的区间索引[^4]。 这种方法在时间效率和空间效率上都具有良好的表现,适用于大规模数据的处理。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值