leetcode_滑动窗口

滑动窗口

这里的滑动窗口不是TCP的滑动窗口,这个滑动窗口更像是一个kmp的匹配过程,其实kmp也属于一个滑动窗口,窗口就是一段特定的区域,滑动顾名思义就是该窗口不是一成不变的。即通过动态的改变一个特定的区域,达到提高算法效率的目的。

/**
 * 最长不重复子串
 */
class Solution_03 {
    public int lengthOfLongestSubstring(String s) {
        int len = s.length();
        if (len == 0) return 0;
        int ans = 0;
        Map m = new HashMap<>();
        for (int start = 0, end = 0; end < len; end++) {
            char alpha = s.charAt(end);
            if (m.containsKey(alpha)) {
                start = Math.max(start, m.get(alpha));
            }
            m.put(alpha, end + 1);
            ans = Math.max(end - start + 1, ans);
        }
        return ans;
    }
}

/**
 * 最小覆盖子串
 */
class Solution_076 {
    public String minWindow(String s, String t) {
        int left = 0, right = 0;
        int start = 0, minLen = Integer.MAX_VALUE;
        //所需要包含得字符串
        Map tInclude = new HashMap<>();
        for (char c : t.toCharArray()) {
            if (tInclude.containsKey(c)) {
                tInclude.put(c, tInclude.get(c) + 1);
            } else {
                tInclude.put(c, 1);
            }
        }
        //类似设置一个滑动窗口
        Map window = new HashMap<>();
        //标志位,用于判断所包含得字符串是否符合要求
        int flag = 0;
        //开始遍历字符串
        while (right < s.length()) {
            char c = s.charAt(right);
            if (tInclude.containsKey(c)) {
                window.put(c, window.containsKey(c) ? window.get(c) + 1 : 1);
                if (window.get(c) == tInclude.get(c)) {
                    flag++;
                }
            }
            right++;
            while (flag == tInclude.size()) {
                if (right - left < minLen) {
                    start = left;
                    minLen = right - left;
                }
                char temp = s.charAt(left);
                if (tInclude.containsKey(temp)) {
                    window.put(temp, window.get(temp) - 1);
                    if (window.get(temp) < tInclude.get(temp)) {
                        flag--;
                    }
                }
                left++;
            }
        }
        return minLen == Integer.MAX_VALUE ? "" : s.substring(start, start + minLen);
    }
}

/**
 * 至多包含两个不同字符的最长子串
 */
class Solution_159 {
    public int lengthOfLongestSubstringTwoDistinct(String s) {
        if (s.length() == 0) return 0;
        int maxLen = -1;
        int right = 0, left = 0;
        int flag = 0;
        Map m = new HashMap<>();
        while (right < s.length()) {
            char c = s.charAt(right);
            if (m.containsKey(c)) {
                m.put(c, m.get(c) + 1);
            } else {
                flag++;
                m.put(c, 1);
            }
            right++;
            while (flag > 2) {
                char c1 = s.charAt(left);
                m.put(c1, m.get(c1) - 1);
                if (m.get(c1) == 0) {
                    flag--;
                }
                left++;
            }
            if (right - left > maxLen) {
                maxLen = right - left;
            }
        }
        return maxLen;
    }
}

/**
 * 至多包含 K 个不同字符的最长子串
 */
class solution_340 {
    public int lengthOfLongestSubstringKDistinct(String s, int k) {
        if (s.length() == 0) return 0;
        int maxLen = -1;
        int right = 0, left = 0;
        int flag = 0;
        Map m = new HashMap<>();
        while (right < s.length()) {
            char c = s.charAt(right);
            if (m.containsKey(c)) {
                m.put(c, m.get(c) + 1);
            } else {
                flag++;
                m.put(c, 1);
            }
            right++;
            while (flag > k) {
                char c1 = s.charAt(left);
                m.put(c1, m.get(c1) - 1);
                if (m.get(c1) == 0) {
                    flag--;
                }
                left++;
            }
            if (right - left > maxLen) {
                maxLen = right - left;
            }
        }
        return maxLen;
    }
}

/**
 * 长度最小的子数组
 * 给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组。如果不存在符合条件的连续子数组,返回 0。
 */
class Solution_209 {
    public int minSubArrayLen(int s, int[] nums) {
        int right = 0, left = 0;
        int minLen = Integer.MAX_VALUE;
        int sum = 0;
        while (right < nums.length) {
            sum = nums[right] + sum;
            right++;
            while (sum > s) {
                sum -= nums[left];
                left++;
                if (right - left < minLen) {
                    minLen = right - left;
                }
            }

        }
        return minLen;
    }
}

/**
 * 滑动窗口最大值
 */
class Solution_239 {
    private int getMaxFormKNums(int[] nums, int left, int right) {
        int flag = left;
        while (left < right) {
            if (nums[left] >= nums[flag]) {
                flag = left;
            }
            left++;
        }
        return flag;
    }

    public int[] maxSlidingWindow(int[] nums, int k) {
        if (k > nums.length) return null;
        int left = 0, right = 0;
        int[] result = new int[nums.length - k + 1];
        int flag = getMaxFormKNums(nums, 0, k);
        //先找到前k个节点中得最大值
        right = k;
        result[left] = nums[flag];
        while (right < nums.length) {
            left++;
            if (flag >= left) {
                if (nums[flag] < nums[right])
                    flag = right;
            } else {
                flag = getMaxFormKNums(nums, left, right + 1);
            }
            result[left] = nums[flag];
            right++;
        }
        return result;
    }
}

/**
 * 字符串的排列
 */
class Solution_567 {
    public boolean checkInclusion(String s1, String s2) {
        int right = 0;
        int match = 0;//标志位
        Map m = new HashMap<>();
        for (char c : s1.toCharArray()) {
            m.put(c, m.getOrDefault(c, 0) + 1);
        }
        Map window = new HashMap<>();
        while (right < s2.length()) {
            char c1 = s2.charAt(right);
            if (m.containsKey(c1)) {
                window.put(c1, window.getOrDefault(c1, 0) + 1);
                if (window.get(c1) == m.get(c1)) {
                    match++;
                }
                if (match == m.size()) return true;
            } else {
                window.clear();
                match = 0;
            }
            right++;
        }
        return false;
    }
}

总结:

一般的滑动窗口会有两个指针,一个指向窗口的头,另一个指向窗口的尾部,通过操作头和尾的指针来达到对不回溯的匹配结果。掌握套路很重要。

你可能感兴趣的:(Leetcode_刷题)