📜  c#中的滑动窗口算法(1)

📅  最后修改于: 2023-12-03 15:29:48.617000             🧑  作者: Mango

C#中的滑动窗口算法

在计算机科学中,滑动窗口算法是一种解决问题的方法,其基本思想是维护一个窗口,该窗口不断地滑动,并根据窗口中的元素来解决问题。

滑动窗口算法通常用于解决数组和字符串问题,例如:找到子数组或子字符串的最大/最小值或其它属性,或者找到满足某些条件的子数组或子字符串的个数。

实现滑动窗口算法

下面是一个简单的用于解决字符串中最长无重复字符子串问题的 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。leftright 分别为窗口的左右边界,起初两个边界重合,都指向起始位置 -1maxLen 记录当前得到的最大子串长度。

在主循环中,我们不断尝试扩大右边界 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)$。

总结

滑动窗口算法是一种非常实用的算法,可以用于很多数组和字符串问题。虽然它的原理比较简单,但是要想掌握滑动窗口算法,还需要一定的实践和经验,没有一定的时间和空间复杂度掌握力,就难以设计出高效的滑动窗口算法。