📅  最后修改于: 2023-12-03 15:29:48.617000             🧑  作者: Mango
在计算机科学中,滑动窗口算法是一种解决问题的方法,其基本思想是维护一个窗口,该窗口不断地滑动,并根据窗口中的元素来解决问题。
滑动窗口算法通常用于解决数组和字符串问题,例如:找到子数组或子字符串的最大/最小值或其它属性,或者找到满足某些条件的子数组或子字符串的个数。
下面是一个简单的用于解决字符串中最长无重复字符子串问题的 C# 滑动窗口算法实现代码:
public static int LengthOfLongestSubstring(string s)
{
if (string.IsNullOrEmpty(s))
return 0;
int[] freq = new int[256];
int left = 0, right = -1;
int maxLen = 0;
while (left < s.Length)
{
if (right + 1 < s.Length && freq[s[right + 1]] == 0)
freq[s[++right]]++;
else
freq[s[left++]]--;
maxLen = Math.Max(maxLen, right - left + 1);
}
return maxLen;
}
这里的 freq
数组用于记录字符出现的频率,初始化为 0。left
和 right
分别为窗口的左右边界,起初两个边界重合,都指向起始位置 -1
;maxLen
记录当前得到的最大子串长度。
在主循环中,我们不断尝试扩大右边界 right
,如果添加字符后没有重复,就继续扩大;否则就需要缩小左边界 left
,直到字符串中的重复字符被剔除掉。
每次窗口操作后,用当前窗口大小来更新 maxLen
,最终返回得到的最大子串长度。
以上代码虽然看起来简单明了,但时间复杂度却是 $O(N^2)$,即要遍历所有子串。实际上,对于一个窗口中的元素,我们每次都只是添加或删除一个,不可能使时间复杂度达到此级别。我们可以通过对此算法进行一定的优化来降低时间复杂度。
我们可以使用哈希表来检测窗口中是否有重复的元素,从而能够实现 $O(1)$ 时间复杂度内的查找。
具体实现可参考下面的代码:
public static int LengthOfLongestSubstring(string s)
{
if (string.IsNullOrEmpty(s))
return 0;
int[] freq = new int[256];
int left = 0, right = -1;
int maxLen = 0;
while (left < s.Length)
{
if (right + 1 < s.Length && freq[s[right + 1]] == 0)
freq[s[++right]]++;
else
freq[s[left++]]--;
maxLen = Math.Max(maxLen, right - left + 1);
}
return maxLen;
}
这里我们使用一个哈希表 freq
来存储窗口内的字符频率。如果添加一个字符后窗口不重复,就将该字符加入哈希表;否则,缩小左端点并从哈希表中删除左端点对应的元素。每次操作完成后更新最大子串长度。优化后的算法时间复杂度为 $O(N)$。
滑动窗口算法是一种非常实用的算法,可以用于很多数组和字符串问题。虽然它的原理比较简单,但是要想掌握滑动窗口算法,还需要一定的实践和经验,没有一定的时间和空间复杂度掌握力,就难以设计出高效的滑动窗口算法。