数组中的灵活思想之一——滑动窗口(附LeetCode实例)

滑动数组的基本思想

在编程中,处理数组(或列表)时,滑动数组是一种非常有用的技术。它通常用于解决需要在连续的子数组或子列表上执行操作的问题。这种技术的关键思想是通过在数组上"滑动"一个固定大小的窗口来解决问题。让我们深入了解滑动数组的原理,并通过相应的示例演示其应用。

滑动数组的基本原理

滑动数组的核心概念是使用两个指针(或索引)来定义一个窗口,并在数组上移动该窗口以执行特定操作。这样的窗口通常是固定大小的,而滑动的步长取决于问题的要求。这种方法的优势在于它能够在线性时间内解决问题,而不需要嵌套的循环。

通常应用场景

1. 寻找子数组中总和的最大/最小值

假设我们有一个包含整数的数组,我们想要找到长度为 k 的子数组的最大值。使用滑动数组的方法,我们可以轻松地在线性时间内解决这个问题。同理,我们找特定条件的子数组也是如此。

ini 复制代码
def max_in_subarray(nums, k):
    max_sum = float('-inf')
    current_sum = 0

    for i in range(len(nums)):
        current_sum += nums[i]

        if i >= k - 1:
            max_sum = max(max_sum, current_sum)
            current_sum -= nums[i - (k - 1)]

    return max_sum

nums = [1, 2, 3, 1, 4, 2, 3]
print(max_in_subarray(nums, k=2))  # 输出6,对应大小为2的子数组为[4,2]
print(max_in_subarray(nums, k=3))  # 输出9,对应大小为3的子数组为[4,2,3]

2. 寻找子数组中的平均值

类似地,我们可以使用滑动数组来找到数组中长度为 k 的子数组的平均值。

less 复制代码
def average_in_subarray(nums, k):
    averages = []

    current_sum = sum(nums[:k])
    averages.append(current_sum / k)

    for i in range(k, len(nums)):
        current_sum += nums[i] - nums[i - k]
        averages.append(current_sum / k)

    return averages

nums = [1, 2, 3, 1, 4, 2, 3]
print(average_in_subarray(nums, k=6))  
# 输出[2.1666666666666665, 2.5],对应计算的子数组为[1, 2, 3, 1, 4, 2],[2, 3, 1, 4, 2, 3]
print(average_in_subarray(nums, k=4))  
# 输出[1.75, 2.5, 2.5, 2.5],对应计算的子数组为[1, 2, 3, 1],[2, 3, 1, 4],[3, 1, 4, 2],[1, 4, 2, 3]

【LeetCode实例:219. 存在重复元素 II

给你一个整数数组 nums 和一个整数 k ,判断数组中是否存在两个 不同的索引 ij ,满足 nums[i] == nums[j]abs(i - j) <= k 。如果存在,返回 true ;否则,返回 false

示例 1:

ini 复制代码
输入: nums = [1,2,3,1], k = 3
输出: true

示例 2:

ini 复制代码
输入: nums = [1,0,1,1], k = 1
输出: true

示例 3:

ini 复制代码
输入: nums = [1,2,3,1,2,3], k = 2
输出: false

提示:

  • 1 <= nums.length <= 10^5
  • -10^9 <= numsi <= 10^9
  • 0 <= k <= 10^5

python题解如下:

python 复制代码
class Solution:
    def containsNearbyDuplicate(self, nums: List[int], k: int) -> bool:
        n = len(nums)
        s = set()
        for i in range(n):
            if i > k:         # 子数组超过k的范围则将子数组(集合s)最前面的元素去掉
                s.remove(nums[i-k-1])
            if nums[i] in s:  # 如果子数组中存在相同的元素则返回True
                return True
            s.add(nums[i])    # 下标小于等于k时,即起始滑窗长度还不足k+1,直接往滑窗将元素nums[i]加入到集合s中
        return False

总结

滑动数组是一种灵活而高效的方法,适用于解决许多与连续子数组有关的问题。通过定义适当大小的窗口,并在数组上移动该窗口,我们可以在线性时间内解决许多复杂的问题。这种技术在处理大规模数据时尤为有用,因为它避免了嵌套循环,提高了算法的效率。在编写代码时,考虑使用滑动数组作为解决问题的工具,以提高代码的可读性和性能。

如果有兴趣的小伙伴也可以去试下209. 长度最小的子数组,此题也是滑动窗口思想解题,本人也是正在学习中,如有错误的地方欢迎大家指正,同时也希望这篇文章能给大家带来帮助。

相关推荐
不能放弃治疗11 分钟前
单 Agent 实现模式
后端
兵慌码乱1 小时前
基于 MediaPipe 与 PySide2 的手势交互音乐控制系统实现:轻量化视觉交互全流程解析
python·opencv·计算机视觉·人机交互·手势识别·mediapipe·pyside2
IT_陈寒2 小时前
Redis内存爆了,原来我漏掉了这个致命配置
前端·人工智能·后端
fliter3 小时前
最后一块拼图:用 bitvec 构造 IPv4 包,真正做出自己的 Ping
后端
luckdewei4 小时前
FastAPI 资产管理系统实战:复杂 ORM 关联、Alembic 迁移与 N+1 查询优化
python
fliter4 小时前
用 Rust 解析并生成 ICMP 包:checksum、nom 与 cookie-factory
后端
蝎子莱莱爱打怪4 小时前
XZLL-IM干货系列 03|消息 ID 设计:一个 UUID 搞不定的事,我用两个 ID 解决了
后端·面试·开源
fliter4 小时前
从 panic 到 Result:用 Rust 重新整理一个 ping 项目的错误处理
后端
森蓝情丶5 小时前
我给 AI 搭了个法庭:一个前端仔的 LangGraph 实战全记录
前端·后端
JensCS猿5 小时前
从 Spring Boot 回看 SSM 框架:手动挡与自动挡的驾驶哲学
后端