【数据结构与算法】关于滑动窗口

写在前面:

这里主要是说数组or字符串问题里边经常会用到的“滑动窗口”,不是网络里边那个(那个其实我也有总结过,不过没整理成博客,等看到那块的时候来写)。

什么是滑动窗口?

画个图先直观的形成一个印象:

 有了印象之后,滑动窗口经常用来解决子串的问题,从图上也能看出来,就是设置一个区间,然后在这个字符串or数组上滑动

有了是什么之后,那我们就看看为什么。

为什么要用滑动窗口

假如我们要求这个字符串里不重复的最长子串长度的话,很自然的想法是里外循环:

我们从头开始找,找到end=3的时候我们发现有重复了,说明从start = 0 开始的最长不重复子串长度是3,然后我们就从start = 1开始再找,当end = 4 时我们发现重复,于是我们继续将start往后推,这样的话是能解决问题的,不过时间复杂度是O(n^{2})。

如果用滑动窗口的话,我们是不是需要判断窗口什么时候移,怎么移?

大概思路就是这样,那怎么直到start每次移动多少呢?

用一个Map<字符,下次的位置>来记录,比如说一开始end = 0的时候我们遍历到字符's',那么我们将它作为key加入map,value则是它的下一个位置,表示说当你遇到‘s’字符时,你滑动到位置开始将不会重复..

怎么实现?

这里是leetcode的第3题:无重复字符的最长子串,上边也是拿它举例的。

 public int lengthOfLongestSubstring(String s){
        int result = 0;
        Map<Character,Integer> map = new HashMap<>();
        for(int start = 0, end = 0; end < s.length(); end++){
            if(map.containsKey(s.charAt(end))){
                start = Math.max(start, map.get(s.charAt(end)));
            }
            map.put(s.charAt(end),end + 1);
            result = Math.max(result,end - start + 1);
        }
        return result;
    }

先写到这,后边遇到这类问题再来补充。

### Python 中滑动窗口算法的实现及应用 滑动窗口是一种高效的算法设计模式,主要用于处理数组或字符串上的子区间问题。它能够将原本需要双重循环遍历的问题优化为单层循环,从而显著降低时间复杂度[^4]。 #### 1. 基本原理 滑动窗口的核心思想是利用双指针维护一个动态变化的窗口区域,在满足特定条件下调整窗口大小并记录最优解。通常情况下,右边界负责扩展窗口,左边界则收缩窗口以保持约束条件成立[^2]。 --- #### 2. 经典问题:无重复字符的最长子串 这是一个典型的滑动窗口应用场景。目标是从给定字符串中找到不包含任何重复字符的最大长度子串。 ##### 实现代码 ```python def length_of_longest_substring(s: str) -> int: char_index_map = {} # 存储字符最近一次出现的位置 max_length = 0 # 记录当前最大长度 start = 0 # 左边界的起始位置 for end, char in enumerate(s): # 遍历字符串,end表示右边界的当前位置 if char in char_index_map and char_index_map[char] >= start: # 如果发现重复字符,则更新左边界的起点 start = char_index_map[char] + 1 # 更新字符最新索引位置 char_index_map[char] = end # 当前窗口长度 current_window_length = end - start + 1 max_length = max(max_length, current_window_length) return max_length ``` 上述代码的时间复杂度为 O(n),其中 n 是输入字符串的长度。这是因为每个字符最多被访问两次(一次由 `start` 指针控制,另一次由 `end` 指针控制)[^1]。 --- #### 3. 另一实例:求和等于 k 的最小子数组长度 此问题是另一种形式的滑动窗口应用,目的是在一个整数数组中找出其和恰好等于指定值 k 的最小连续子数组长度。 ##### 实现代码 ```python def min_subarray_len(nums: list[int], target_sum: int) -> int: min_length = float('inf') # 初始化为无穷大 window_sum = 0 # 窗口内的总和 start = 0 # 左边界初始位置 for end in range(len(nums)): # 遍历整个数组 window_sum += nums[end] # 扩展窗口右侧 while window_sum >= target_sum: # 收缩左侧直到不再符合条件 min_length = min(min_length, end - start + 1) window_sum -= nums[start] start += 1 return min_length if min_length != float('inf') else 0 ``` 这段代码同样基于滑动窗口的思想,通过不断调整左右边界来寻找满足条件的最小区间。 --- #### 4. 使用场景拓展 除了以上两种经典例子外,滑动窗口还可以应用于其他领域: - **机器学习中的特征提取** 当面对高维时序数据时,可以通过定义固定宽度的滑动窗口截取片段作为模型输入[^5]。 - **实时流数据分析** 例如监控系统性能指标或者金融交易信号检测等场合下都需要快速统计一段时间范围内的汇总信息。 --- #### 5. 性能分析 相比暴力枚举所有可能组合的方式,滑动窗口极大地减少了不必要的计算量。然而需要注意的是,并不是所有的题目都适合直接套用标准模板;有时还需要结合具体需求做出适当修改才能达到最佳效果。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值