滑动窗口技巧详解
什么是滑动窗口
滑动窗口是一种常用的算法技巧,适用于处理数组、字符串等序列数据的子集或子串的问题。它通过维护一个窗口(通常是两个指针表示的区间),在遍历的过程中实现窗口的滑动,从而解决特定问题。
滑动窗口的基本思想
-
定义窗口的起始位置和结束位置:通过两个指针(通常是
left
和right
)定义窗口的起始和结束位置。 -
动态调整窗口大小:随着遍历的进行,通过移动指针动态调整窗口的大小,以适应问题的要求。
-
实时更新结果:在窗口滑动的过程中,实时更新问题的结果,通常是最大值、最小值、子串长度等。
滑动窗口的应用场景
滑动窗口技巧广泛应用于以下类型的问题:
-
子数组/子串问题:求解最大、最小或满足特定条件的子数组或子串。
-
子序列问题:求解最长、最短或满足特定条件的子序列。
-
固定大小的窗口问题:例如计算窗口内的平均值、求和等。
-
字符串匹配问题:在两个字符串中寻找匹配的子串。
滑动窗口的步骤
-
初始化窗口:定义两个指针,分别表示窗口的起始位置和结束位置。初始化其他必要的变量,如结果变量。
-
遍历序列:使用右指针进行遍历,扩展窗口。
-
更新窗口:根据问题的要求,通过移动左指针或右指针,动态调整窗口的大小。
-
实时更新结果:在窗口滑动的过程中,实时更新问题的结果。
-
返回结果:返回最终结果。
示例:最长半重复子字符串问题的解法
class Solution:
def longestSemiRepetitiveSubstring(self, s: str) -> int:
left = 0
n = len(s)
ans = 1
pair = 0
for right in range(1, n):
if s[right] == s[right - 1]:
pair += 1
while pair > 1:
left += 1
if s[left] == s[left - 1]:
pair -= 1
ans = max(ans, right - left + 1)
return ans
在这个示例中,我们使用滑动窗口技巧解决了最长半重复子字符串的问题。通过维护两个指针left
和right
,动态调整窗口大小,并实时更新最终结果ans
,最终得到问题的解答。
滑动窗口技巧是解决一类问题的通用方法,通过合理设计窗口的滑动规则,可以高效地解决多种问题。
找到最长的半重复子字符串
问题描述
给定一个下标从0开始的字符串s,该字符串仅包含0到9的数字字符。如果一个字符串t中至多有一对相邻字符是相等的,那么称这个字符串t是半重复的。例如,“0010”、“002020”、“0123”、"2002"和"54944"是半重复字符串,而"00101022"和"1101234883"不是。请你返回s中最长半重复子字符串的长度。
一个子字符串是一个字符串中一段连续非空的字符。
示例
示例1:
输入: s = “52233”
输出: 4
解释: 最长半重复子字符串是 “5223”,子字符串从i = 0开始,在j = 3处结束。
示例2:
输入: s = “5494”
输出: 4
解释: s就是一个半重复字符串,所以答案为4。
示例3:
输入: s = “1111111”
输出: 2
解释: 最长半重复子字符串是 “11”,子字符串从i = 0开始,在j = 1处结束。
提示:
- 1 <= s.length <= 50
- ‘0’ <= s[i] <= ‘9’
解决方案
class Solution:
def longestSemiRepetitiveSubstring(self, s: str) -> int:
left = 0
n = len(s)
ans = 1
pair = 0
for right in range(1, n):
if s[right] == s[right - 1]:
pair += 1
while pair > 1:
left += 1
if s[left] == s[left - 1]:
pair -= 1
ans = max(ans, right - left + 1)
return ans
详细步骤解析
-
初始化指针
left
为0,字符串长度n
为s
的长度,初始化最终结果ans
为1,pair
为0,用于记录相邻字符相等的对数。 -
使用指针
right
从1到n-1进行遍历,表示当前字符的下标。 -
如果
s[right]
等于s[right - 1]
,说明找到相邻字符相等的一对,此时pair
加1。 -
进入while循环,当
pair
大于1时,表示有多余的相邻字符相等的对数,需要移动left
指针。 -
在while循环中,每次移动
left
指针,如果s[left]
等于s[left - 1]
,说明当前位置也是相邻字符相等的一对,此时pair
减1。 -
在遍历的过程中,更新最终结果
ans
为当前窗口的长度right - left + 1
的最大值。 -
返回最终结果
ans
,即最长半重复子字符串的长度。
该算法使用同向双指针的技巧,通过维护一个窗口,动态更新窗口的起始位置left
,以及统计相邻字符相等的对数pair
,最终得到最长半重复子字符串的长度。