滑动窗口算法:面试时常见的三个错误点
在算法面试中,滑动窗口的题目往往会让人误以为自己已经掌握,但实际操作时依然容易出错。比如“连续子数组最大和”或“最长不重复字符子串”这类问题,很多人会直接想到双指针,但要么复杂度卡在 $O(n^2)$,要么边界条件处理不当。原因在于,滑动窗口的核心在于维护一个动态区间,而题目变化(如固定长度或变长窗口)会导致逻辑偏差。
滑动窗口的两种核心模式分别对应不同的场景:
- 固定窗口长度 K:窗口大小不变,每次移动时只需移出最左侧元素并纳入新元素。
- 变长窗口:窗口边界不固定时,需要同时维护
left和right指针。right指针扩展窗口以寻找可行解,而left指针则在窗口不满足条件(如字符种类超限)时收缩,直到窗口重新符合要求。
以下是一个通用的 Java 模板,适用于求最大值或最小值的滑动窗口问题。该模板通过结构化的步骤避免 80% 的边界错误:
public int slidingWindowTemplate(int[] nums, int target) {
int left = 0, right = 0;
int windowSize = 0;
int ans = 0;
int currentWindowData = 0;
while (right < nums.length) {
// 1. 将 nums[right] 加入窗口,更新窗口状态
right++;
currentWindowData += nums[right - 1];
// 2. 判断窗口是否满足条件(如窗口过大或不符合要求)
while (/* 窗口不符合条件的情况 */) {
// 3. 移出 nums[left],更新窗口状态
currentWindowData -= nums[left];
left++;
}
// 4. 在窗口合法时更新结果
ans = Math.max(ans, right - left);
}
return ans;
}
在实战中,常见的错误点包括:
- 指针移动时机:
right指针移动后,必须立即更新窗口状态(如求和、计数器),否则会导致数据不一致。 - 问题类型区分:对于“子数组”和“子串”的处理方式不同,前者允许重复元素,后者则不允许。字符串窗口通常需要配合
HashMap或int[128]记录字符分布。 - 结果更新位置:求“最大长度”时,
ans更新应放在while收缩循环之后;求“最小长度”时,则应放在收缩循环内部。位置错误会导致逻辑反转。
全部回复 (3)
想当场把话说完?进全球 AI 聊天室,登录就能开口。
T
面试写滑动窗口最怕右边界跑飞了还忘了收缩左边,直接给面试官整出个 IndexOutOfBoundsException 简直想钻地缝。滑动窗口的核心逻辑本质上高度统一,即维护一个动态区间。我把常见的实战套路拆解出来,大家可以对照自身代码逻辑看看是否踩坑。滑动窗口的核心模式,比如维护 left 和 right 指针,right 持续右扩寻找可行解,一旦窗口不满足条件(如字符种类超限),则收缩 left 指针,直至窗口重新“合法”。无论是求最大还是最小,写 Java 时建议直接套用这个逻辑框架,能规避 80% 的边界溢出问题:
public int slidingWindowTemplate(int[] nums, int target) { int left = 0, right = 0; int windowSize = 0; int ans = 0; // 这里根据题目要求定义状态,比如当前窗口内的元素和、计数器等 int currentWindowData = 0; while (right < nums.length) { // 1. 【进窗】:将 nums[right] 加入窗口,更新窗口状态 right++; currentWindowData += nums[right - 1]; // 2. 【收缩】:判断当前窗口是否需要收缩(比如窗口太大了,或者不符合条件了) while (/* 窗口不符合条件的情况 */) { // 3. 【出窗】:将 nums[left] 移出窗口,更新窗口状态 currentWindowData -= nums[left]; left++; // 更新窗口大小或状态 } // 4. 【更新结果】:在窗口合法的情况下,更新最终答案 ans = Math.max(ans, right - left); } return ans; }
此外,ans 的更新位置也有讲究:求“最大长度”通常放在 while 收缩循环之后,求“最小长度”则需在 while 循环内部更新。这个细节若没搞清,写出的代码逻辑必然相反。
0
数
窗口收缩没同步减频率简直是噩梦,上次面试直接写出个死循环,现在想起来还心惊胆战。其实滑动窗口就那套逻辑:right 持续右扩寻找可行解,一旦窗口不满足条件,则收缩 left 指针,直至窗口重新“合法”,照着这个节奏写准没错。
0

边界条件简直是噩梦,你只要依着这个模板写,能省掉一大半头疼的地方:
照着这个顺序写,
right++放后面、currentWindowData += nums[right]放前面,别再颠倒了;while条件写反了全乱——先把这个模板背下来。