滑动窗口

最小覆盖子串

class Solution {
    public String minWindow(String s, String t) {
        int[] a = new int[128];
        for (char ch : t.toCharArray()) {
            a[ch]++;
        }
        int[] b = new int[128];
        int left = 0, right = 0, l = 0, min = s.length() + 1;
        char[] arr = s.toCharArray();
        int dis = 0; //窗口内与t相同的数量

        for (int i = 0; i < arr.length; i++) {
            if (a[arr[i]] > 0) {
                b[arr[i]]++;
                if (b[arr[i]] <= a[arr[i]]) { //如果大于就不算进去了。因为大于也满足。
                    dis++;
                }
            }
            if (dis == t.length()) {
                //左指针移动条件:arr[l]不在t内或者arr[l]在窗口内部的数量大于t中arr[l]的数量
                while (a[arr[l]] == 0 || b[arr[l]] > a[arr[l]]) { 
                    if (a[arr[l]] > 0) {
                        b[arr[l]]--;
                    }
                    l++;
                }
                if (i - l + 1 < min) {
                    left = l;
                    right = i;
                    min = i - l + 1;
                }
            }
        }

        return min == s.length() + 1 ? "" : s.substring(left, right + 1);
    }
}

 

长度最小的子数组

class Solution {
    public int minSubArrayLen(int s, int[] nums) {
        int sum = 0, l = 0, min = nums.length + 1;
        for (int i = 0; i < nums.length; i++) {
            sum += nums[i];
            //窗口滑动的条件是找到使得sum > s 的最大 l
            while (sum > s) {
                if (sum - nums[l] < s) break;
                sum -= nums[l];
                l++;
            }
            if (sum >= s && i - l + 1 < min) {
                min = i - l + 1;
            } 
        }
        return min == nums.length + 1 ? 0 : min;
    }
}

 

替换后的最长重复字符

class Solution {
    public int characterReplacement(String s, int k) {
        if (k + 1 > s.length()) return s.length();
        int[] a = new int[26];
        int l = 0, max = k + 1;
        char[] cs = s.toCharArray();
        for (int i = 0; i < cs.length; i++) {
            a[cs[i]-'A']++;
            //l 移动的条件是当前窗口里面的数量最多的那个数字+k也不能填满窗口
            while (l <= i && max(a) + k < i - l + 1) {
                a[cs[l] - 'A']--;
                l++;
            }
            max = Math.max(max, i - l + 1);
        }
        return max;
    }

    private int max(int[] A) {
        int max = 0;
        for (int i = 0; i < 26; i++) {
            max = Math.max(max, A[i]);
        }
        return max;
    }
}

其实可以优化一下

class Solution {
    public int characterReplacement(String s, int k) {
        int dis = 0, l = 0, res = 0;
        int[] a = new int[26];
        char[] cs = s.toCharArray();

        for (int i = 0; i < cs.length; i++) {
            a[cs[i] - 'A']++;
            //因为当窗口缩短时,不会出现窗口内相同元素的数量大于dis的情况
            dis = Math.max(a[cs[i] - 'A'], dis);
            while (dis + k < i - l + 1) {
                a[cs[l] - 'A']--;
                l++;
            }
            res = Math.max(res, i - l + 1);
        }

        return res;
    }
}

 

找到字符串中所有字母异位词

窗口固定

class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        int[] a = new int[26];
        int[] b = new int[26];
        List<Integer> list = new ArrayList<>();
        for (char ch : p.toCharArray()) {
            a[ch-'a']++;
        }
        char[] arr = s.toCharArray();
        int n = p.length();
        for (int i = 0; i < arr.length; i++) {
            b[arr[i]-'a']++;
            if (i - n >= 0) {
                b[arr[i - n]-'a']--;
            }
            boolean mark = true;
            for (int j = 0; j < 26; j++) {
                if (a[j] != b[j]) {
                    mark = false;
                    break;
                } 
            }
            if (mark) list.add(i - n + 1);
        }
        return list;
    }
}

窗口不固定

class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        List<Integer> res = new ArrayList<>();
        int[] a = new int[26];
        for (char ch : p.toCharArray()) {
            a[ch - 'a']++;
        }
        int l = 0;
        int[] b = new int[26];
        char[] cs = s.toCharArray();

        for (int i = 0; i < cs.length; i++) {
            b[cs[i] - 'a']++;
            //左指针移动的条件是如下,每次i++就进行如下判断,就可以放心地移动左指针了。
            while (b[cs[i] - 'a'] > a[cs[i] - 'a']) {
                b[cs[l] - 'a']--;
                l++;
            }
            if (i - l + 1 == p.length()) {
                res.add(l);
            }
        }
        return res;
    }
}

 

字符串的排列

这个题和上面写法一模一样

class Solution {
    public boolean checkInclusion(String s1, String s2) {
        int[] a = new int[26];
        for (char ch : s1.toCharArray()) {
            a[ch - 'a']++;
        }
        int[] b = new int[26];
        int l = 0;
        char[] cs = s2.toCharArray();

        for (int i = 0; i < cs.length; i++) {
            b[cs[i] - 'a']++;
            while (b[cs[i] - 'a'] > a[cs[i] - 'a']) {
                b[cs[l] - 'a']--;
                l++;
            }
            if (i - l + 1 == s1.length()) {
                return true;
            }
        }
        return false;
    }
}

 

posted @ 2021-01-10 23:13  CPJ31415  阅读(94)  评论(0)    收藏  举报