【力扣分模块练习】滑动窗口

这篇博客探讨了如何使用滑动窗口解决三种不同的数组操作问题:1)找到最多可以将K个0变为1的最长连续1子数组;2)寻找绝对差不超过限制的最长连续子数组;3)在书店老板生气问题中最大化顾客满意度。通过维护窗口内的状态,如0的个数、最大值和最小值,可以有效地解决这些问题。滑动窗口方法在处理数组和字符串问题时是一种强大的工具。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1004. 最大连续1的个数 III
给定一个由若干 0 和 1 组成的数组 A,我们最多可以将 K 个值从 0 变成 1 。
返回仅包含 1 的最长(连续)子数组的长度。

示例 1:
输入:A = [1,1,1,0,0,0,1,1,1,1,0], K = 2
输出:6
解释:
[1,1,1,0,0,1,1,1,1,1,1]
粗体数字从 0 翻转到 1,最长的子数组长度为 6。

题解:
基本上来说,M级别或以下的滑窗题只要翻译对了题目是比较容易的。总结了要点有以下两点:
1.争取把题目翻译成“找出XXX样的最长连续子串”
2.找最长的时候,记得最后只需要保证left和right被撑到最大,然后一直移动到末端就可以了。而不用具体的找出是哪段数据最长。

如本题:
[最多可以把 K 个 0 变成 1,求仅包含 1 的最长子数组的长度]转换为 [找出一个最长的子数组,该子数组内最多允许有 K 个 0 ]。

//找出变换K个最长的1,即找出最多包含K个0的最长子列
class Solution {
public:
	int longestOnes(vector<int>& A, int K) {
		int left = 0;
		int zero = 0;
		int i = 0;
		for (; i < A.size(); i++)
		{
			if (A[i] == 0)
				zero++;
			if (zero > K)
			{
                if (A[left] == 0)
					zero--;
				left++;			//如果0数量超标,左指针才会移动
			}
		}
		return i - left;
	}
};

1438. 绝对差不超过限制的最长连续子数组
给你一个整数数组 nums ,和一个表示限制的整数 limit,请你返回最长连续子数组的长度,该子数组中的任意两个元素之间的绝对差必须小于或者等于 limit 。
如果不存在满足条件的子数组,则返回 0 。

示例:
输入:nums = [10,1,2,4,7,2], limit = 5
输出:4
解释:满足题意的最长子数组是 [2,4,7,2],其最大绝对差 |2-7| = 5 <= 5 。

题解:
本题核心,维护窗口内最大值和最小值。我用的map,官方题解用的multiset,其实差不多。要注意multiset也是自动排序的,默认小到大,与set的区别就是可以允许有重复元素出现。

此外,用rbegin()表示最后一个元素。这个意思是,反向遍历的头元素。

class Solution {
public:
	int longestSubarray(vector<int>& nums, int limit) {
		map<int,int> mp; //利用按键值大小排序

		int left = 0;
		int i = 0;
		for (; i < nums.size(); i++)
		{
			if (mp.count(nums[i]))//出现过
				mp[nums[i]]++;
			else
				mp.insert({ nums[i],1 });

			int minn = mp.begin()->first;
			int maxn = mp.rbegin()->first;
			if (abs(maxn - minn) > limit)
			{
				//踢出一个left更新map
				if (mp[nums[left]] == 1)
					mp.erase(nums[left]);
				else
					mp[nums[left]]--;

				left++; //左指针右移
			}
		}
		
		return i - left;
	}
};

1052. 爱生气的书店老板
今天,书店老板有一家店打算试营业 customers.length 分钟。每分钟都有一些顾客(customers[i])会进入书店,所有这些顾客都会在那一分钟结束后离开。
在某些时候,书店老板会生气。 如果书店老板在第 i 分钟生气,那么 grumpy[i] = 1,否则 grumpy[i] = 0。 当书店老板生气时,那一分钟的顾客就会不满意,不生气则他们是满意的。
书店老板知道一个秘密技巧,能抑制自己的情绪,可以让自己连续 X 分钟不生气,但却只能使用一次。
请你返回这一天营业下来,最多有多少客户能够感到满意的数量。

示例:
输入:customers = [1,0,1,2,1,1,7,5], grumpy = [0,1,0,1,0,1,0,1], X = 3
输出:16
解释:
书店老板在最后 3 分钟保持冷静。
感到满意的最大客户数量 = 1 + 1 + 1 + 1 + 7 + 5 = 16.

题解:简单题,只要读懂题意很好理解。维护一个大小为K的窗口,依次看这个窗口比之前的情况增加了多少,然后选择这些窗口中增加最大的情况。因为除了窗口之外的和是固定的,增加的越多,处理后的和也就越大。

class Solution {
public:
	int maxSatisfied(vector<int>& customers, vector<int>& grumpy, int X) {
		int n = customers.size();
		//异或处理,方便后面直接用乘法
        for (int i = 0; i < n; i++)
			grumpy[i] = grumpy[i] ^ 1;

		int more = 0, sum = 0;
		for (int i = 0; i < X; i++) //初始化第一个窗口
		{
			more += customers[i] - (customers[i] * grumpy[i]);
			sum += (customers[i] * grumpy[i]); //顺便统计原始和
		}
		
		int maxmore = more;
		for (int i = X; i < n; i++)
		{
			int left = i - X;
			more -= customers[left] - (customers[left] * grumpy[left]); //踢掉左边指针
			more += customers[i] - (customers[i] * grumpy[i]);//加入右边指针

			maxmore = max(maxmore, more);
			sum += (customers[i] * grumpy[i]);//顺便统计原始和
		}

		return sum + maxmore;
	}
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值