文章目录
须知
💬 欢迎讨论:如果你在学习过程中有任何问题或想法,欢迎在评论区留言,我们一起交流学习。你的支持是我继续创作的动力!
👍 点赞、收藏与分享:觉得这篇文章对你有帮助吗?别忘了点赞、收藏并分享给更多的小伙伴哦!你们的支持是我不断进步的动力!
🚀 分享给更多人:如果你觉得这篇文章对你有帮助,欢迎分享给更多对C++算法感兴趣的朋友,让我们一起进步!
1. C++ 滑动窗口算法详解
1.1 滑动窗口算法重要性
滑动窗口(Sliding Window)是一种高效的算法思想,广泛应用于数组和字符串问题,特别是涉及子数组、子字符串、窗口内统计等场景。它的重要性在于:
- 提升效率:通过动态调整窗口范围,避免暴力枚举所有可能的子区间,从而将时间复杂度从 O(N^2) 或更高优化到 O(N)。
- 简化逻辑:滑动窗口提供了一个统一的框架,可以直观地处理许多问题,如最大/最小子数组和、子数组个数统计等。
- 实际应用广泛:在数据流、字符串处理、窗口内最值计算等领域具有广泛应用。
本文将通过简单的例题来讲解“同向双指针”算法的不同应用,以及如何在 C++ 中实现。同向双指针也称为“滑动窗口”。
1.2 什么是滑动窗口?
滑动窗口是一种动态调整区间范围的算法。它将问题中的“窗口”定义为一段连续的子数组或子字符串,并通过增加或减少窗口的左右边界来动态计算结果。窗口的范围会随着问题的需求而“滑动”,从而优化问题求解过程。
窗口的两种典型类型:
- 固定窗口:窗口大小固定,通过滑动计算覆盖不同的区间。
- 可变窗口:窗口大小可变,根据条件动态调整范围。
1.3 核心思想
滑动窗口的核心思想是:
通过一对指针(通常为左右指针
left
和right
),定义一个“窗口”,然后在窗口内进行动态计算。
实现步骤:
- 初始化窗口:定义窗口的起点(
left
)和终点(right
),一般初始为 0。 - 扩展窗口:通过移动
right
指针扩展窗口,直到窗口内满足特定条件。 - 缩小窗口:当窗口满足条件时,移动
left
指针缩小窗口,同时更新结果。 - 重复上述过程:直到
right
指针遍历完整个数组或字符串。
关键点:
- 动态调整窗口的范围。
- 记录窗口内的状态(如当前和、频率计数等)。
- 根据问题需求判断何时更新结果。
1.4 滑动窗口的应用场景
- 求解固定长度的子数组/子字符串问题:
- 如最大或最小子数组和,最长不重复子字符串。
- 求解动态条件的区间问题:
- 如满足条件的最短子数组,窗口内的元素个数统计。
- 在线算法和数据流问题:
- 滑动窗口可以在数据流中实时计算指标。
2. 滑动窗口的逻辑可以归纳为以下模板:
int slidingWindow(vector<int>& nums, int target)
{
int left = 0, current_sum = 0, result = INT_MAX;
for (int right = 0; right < nums.size(); ++right)
{
current_sum += nums[right]; // 扩展窗口
while (current_sum >= target)// 符合条件,尝试缩小窗口
{
result = min(result, right - left + 1);
current_sum -= nums[left++]; // 移动左边界,缩小窗口
}
}
return result == INT_MAX ? 0 : result; // 如果没找到满足条件的子数组返回 0
}
3. 题目1:长度最小的子数组
题目链接:209. 长度最小的子数组 - 力扣(LeetCode)
题目描述:
3.1 算法思路:
3.1.1 初始化变量:
start
和end
:- 两个指针分别表示滑动窗口的左边界和右边界。
start
用于缩小窗口,end
用于扩展窗口。
ret
:- 记录满足条件的最小子数组长度,初始化为
INT_MAX
(一个很大的值)。
- 记录满足条件的最小子数组长度,初始化为
sum
:- 维护当前窗口内元素的总和。
3.1.2 扩展窗口:
通过 for
循环移动右边界 end
:
- 每次加入
nums[end]
到sum
中,表示将当前元素纳入窗口。 - 目的:不断扩大窗口直到窗口内的和满足条件。