不定长滑动窗口

92 阅读2分钟

求最长/最大

1. 无重复字符的最长子串

维护一个动态滑动窗口,当新入的字符已经存在时,收缩左区间直到该字符不重复

class Solution {
    public int lengthOfLongestSubstring(String S) {
        char[] s = S.toCharArray();
        int ans = 0, left = 0;
        boolean[] had = new boolean[128];
        for (int right = 0; right < s.length; right++) {
            char c = s[right];
            while (had[c]) {
                had[s[left++]] = false;
            }
            had[c] = true;
            ans = Math.max(ans, right - left + 1);
        }
        return ans;
    }
}

2. 每个字符最多出现两次的最长子字符串

在上一题的基础上稍微改动,允许一个字符出现两次,先将字符加入到区间当中,再来判断是否超过两个重复的字符,如果是则收缩左区间直到该字符最多仅出现两次

class Solution {
    public int maximumLengthSubstring(String S) {
        int ans = 0, left = 0;
        char[] s = S.toCharArray();
        int[] has = new int[128];
        for (int right = 0; right < s.length; right++) {
            char c = s[right];
            has[c]++;
            while (has[c] > 2) {
                has[s[left++]]--;
            }
            ans = Math.max(ans, right - left + 1);
        }
        return ans;
    }
}

3. 删掉一个元素以后全为 1 的最长子数组

删除一个元素以后全为 1 的最长子数组,即求最多含有 1 个 0 的最长子数组。维护一个动态滑动窗口,当 0 的数量超过 1 个时收缩左区间

class Solution {
    public int longestSubarray(int[] nums) {
        int ans = 0, left = 0, count = 0;
        for (int right = 0; right < nums.length; right++) {
            if (nums[right] == 0) count++;
            while (count > 1) {
                if (nums[left++] == 0) {
                    count--;
                }
            }
            ans = Math.max(ans, right - left + 1);
        }
        return ans - 1;
    }
}

4. 尽可能使字符串相等

维护一个动态的滑动窗口,窗口的值为两个字符串之间的差值,限制为差值之和最多为 maxCost

使用一个 sumCost 记录当前窗口的差值和,当达到阈值时收缩左边界(left++)

class Solution {
    public int equalSubstring(String S, String T, int maxCost) {
        int ans = 0, left = 0, sumCost = 0;
        char[] s = S.toCharArray(), t = T.toCharArray();
        for (int right = 0; right < s.length; right++) {
            sumCost += Math.abs(s[right] - t[right]);
            while (sumCost > maxCost) {
                sumCost -= Math.abs(s[left] - t[left]);
                left++;
            }
            ans = Math.max(ans, right - left + 1);
        }
        return ans;
    }
}

5. 找到最长的半重复子字符串

用 count 记录相邻字符相等的数目,当达到阈值(即大于 1 对)时,收缩左边界直到最多仅有 1 对相邻相等的字符

class Solution {
    public int longestSemiRepetitiveSubstring(String S) {
        char[] s = S.toCharArray();
        int ans = 0, left = 0, count = 0;
        if (s.length == 1)
            return 1;
        for (int right = 1; right < s.length; right++) {
            if (s[right] == s[right - 1]) {
                count++;
            }
            while (count > 1) {
                if (s[left] == s[left + 1]) {
                    count--;
                }
                left++;
            }
            ans = Math.max(ans, right - left + 1);
        }
        return ans;
    }
}