☰
LeetCode算法实战:滑动窗口与螺旋矩阵技巧详解
2026/11/4 12:24:01 网站建设 项目流程

1. 算法刷题实战:滑动窗口与模拟转圈

今天要分享的是两道非常经典的LeetCode题目——209题「长度最小的子数组」和59题「螺旋矩阵II」。这两道题分别代表了数组操作中两种重要的解题思路:滑动窗口技巧和模拟转圈法。作为刷过300+题的过来人,我觉得这两道题特别适合用来培养算法直觉。

2. 209. 长度最小的子数组

2.1 问题重述与暴力解法

给定一个含有n个正整数的数组和一个正整数target,找出该数组中满足其和≥target的长度最小的连续子数组,并返回其长度。如果不存在符合条件的子数组,返回0。

最直观的暴力解法是双重循环枚举所有可能的子数组:

def minSubArrayLen(target, nums): n = len(nums) min_len = float('inf') for i in range(n): current_sum = 0 for j in range(i, n): current_sum += nums[j] if current_sum >= target: min_len = min(min_len, j - i + 1) break return min_len if min_len != float('inf') else 0

这个解法时间复杂度是O(n²),在LeetCode上会超时。我们需要更聪明的办法。

2.2 滑动窗口的精髓

滑动窗口的核心思想是维护一个窗口,通过调整窗口的左右边界来寻找最优解。具体到这道题:

  1. 初始化左指针left=0,当前和current_sum=0,最小长度min_len=∞
  2. 右指针right从0开始遍历数组:
    • 将nums[right]加入current_sum
    • 当current_sum≥target时:
      • 更新min_len
      • 尝试左移left缩小窗口
  3. 最后返回min_len

优化后的代码:

def minSubArrayLen(target, nums): n = len(nums) min_len = float('inf') left = current_sum = 0 for right in range(n): current_sum += nums[right] while current_sum >= target: min_len = min(min_len, right - left + 1) current_sum -= nums[left] left += 1 return min_len if min_len != float('inf') else 0

关键点:为什么用while而不是if?因为左边界可能需要多次移动才能满足current_sum<target的条件。

2.3 复杂度分析与边界情况

时间复杂度:O(n),每个元素最多被访问两次(右指针一次,左指针一次) 空间复杂度:O(1),只使用了常数个额外空间

需要注意的特殊情况:

  • 空数组输入
  • 数组中所有元素和仍小于target
  • 数组中存在单个元素就≥target的情况

3. 59. 螺旋矩阵II

3.1 问题理解与模拟思路

给定正整数n,生成一个包含1到n²所有元素,且元素按顺时针螺旋排列的n×n正方形矩阵。

这道题的关键在于准确模拟填充过程。我们需要:

  1. 确定填充的层数(n为奇数时需要单独处理中心点)
  2. 按照"右→下→左→上"的顺序填充每一圈
  3. 维护当前填充的数字和边界条件

3.2 分层填充的实现细节

具体实现时可以定义四个边界:

  • 左边界left=0
  • 右边界right=n-1
  • 上边界top=0
  • 下边界bottom=n-1

然后按照以下步骤填充:

def generateMatrix(n): matrix = [[0]*n for _ in range(n)] num = 1 left, right, top, bottom = 0, n-1, 0, n-1 while left <= right and top <= bottom: # 从左到右填充上边 for i in range(left, right+1): matrix[top][i] = num num += 1 top += 1 # 从上到下填充右边 for i in range(top, bottom+1): matrix[i][right] = num num += 1 right -= 1 # 从右到左填充下边 for i in range(right, left-1, -1): matrix[bottom][i] = num num += 1 bottom -= 1 # 从下到上填充左边 for i in range(bottom, top-1, -1): matrix[i][left] = num num += 1 left += 1 return matrix

3.3 调试技巧与常见错误

这类模拟题最容易出现的问题:

  1. 边界条件处理不当(特别是奇数n的中心点)
  2. 填充顺序错误(必须严格遵循右→下→左→上)
  3. 索引越界(尤其在反向填充时)

调试时可以:

  • 打印每步后的矩阵状态
  • 使用小规模n(如n=3)手动模拟验证
  • 特别注意循环终止条件

4. 两道题的共通技巧

虽然这两道题解法不同,但都体现了算法题的一些通用技巧:

  1. 先考虑暴力解法,再优化
  2. 画图辅助理解(特别是螺旋矩阵)
  3. 使用小规模测试案例验证
  4. 注意边界条件和特殊输入

对于滑动窗口,关键是要理解:

  • 何时移动右边界(扩展窗口)
  • 何时移动左边界(收缩窗口)
  • 如何更新最优解

对于模拟题,最重要的是:

  • 明确填充顺序和规则
  • 准确维护边界条件
  • 处理奇数/偶数不同情况

5. 刷题进阶建议

  1. 同类题目推荐:

    • 滑动窗口:3(无重复字符最长子串)、76(最小覆盖子串)、904(水果成篮)
    • 螺旋矩阵:54(螺旋矩阵)、885(螺旋矩阵III)
  2. 时间控制:

    • 每道题给自己设定时间限制(如30分钟)
    • 超过时间就参考题解,但必须完全理解
  3. 反复练习:

    • 隔几天重新做这两道题
    • 尝试不同语言实现
  4. 总结模板:

    • 滑动窗口有相对固定的代码结构
    • 模拟题要总结自己的坐标处理方式

我在最初做这两道题时,螺旋矩阵花了整整两个小时才AC。后来发现其实只要坚持按照固定方向模拟,注意边界调整,这类题就会变得很有规律。而滑动窗口的难点在于理解为什么它能降低复杂度,这需要对双指针有深刻理解。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询