我的滑动窗口——在困难的力扣题上提交提交

1 概要

本文将梳理出 LeetCode 上关于滑动窗口类型的题目,前期笔者可能忙于刷题,暂时只能通过的代码贴在这里,后序有时间慢慢补充分析和思路。喜欢的可以点赞、关注一波~

2 实战

2.1 固定滑动窗口

2.1.1 【1456.定长子串中元音的最大数目】

1456. 定长子串中元音的最大数目

class Solution {
    public int maxVowels(String s, int k) {
        if (s == null || s.length() == 0) {
            throw new IllegalArgumentException();
        }
        char[] chs = s.toCharArray();
        int length = chs.length;
        int cntVowel = 0;
        for (int i = 0; i < k; i++) {
            cntVowel += getVowelCnt(chs[i]);
        }

        int res = cntVowel;
        for (int i = k; i < length; i++) {
            cntVowel += getVowelCnt(chs[i]) - getVowelCnt(chs[i - k]);
            res = Math.max(res, cntVowel);
        }

        return res;
    }

    private int getVowelCnt(char c) {
        return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u' ? 1 : 0;
    }
}

2.1.2 【1423. 可获得的最大点数】

1423. 可获得的最大点数

class Solution {
    public int maxScore(int[] cardPoints, int k) {
        // 由于是从头或者尾抽取 k 张牌,所以剩下的 len - k 张牌一定是连续的。求抽取的最大,那就是 len - k 剩下的最小
        int length = cardPoints.length;
        int windowSize = length - k;
        // 形成 window
        int windowSum = 0;
        int sumAll = 0;
        for (int i = 0; i < windowSize; i++) {
            sumAll += cardPoints[i];
            windowSum += cardPoints[i];
        }
        int windowMinSum = windowSum;
        for (int i = windowSize; i < length; i++) {
            sumAll += cardPoints[i];
            windowSum += cardPoints[i] - cardPoints[i - windowSize];
            windowMinSum = Math.min(windowMinSum, windowSum);
        }

        return sumAll - windowMinSum;
    }
}

2.1.3 【1658. 将 x 减到 0 的最小操作】

1658. 将 x 减到 0 的最小操作数

class Solution {
    public int minOperations(int[] nums, int x) {
        // 思路同取牌那道题目,转换为求窗口和为 sum - x 的最大窗口
        if (nums == null || nums.length == 0) {
            throw new IllegalArgumentException();
        }

        int length = nums.length;
        int target = Arrays.stream(nums).sum() - x;
        int left = 0, right = 0;
        int windowSize = -1;
        while (right < length) {
            target -= nums[right++];
            while (left < right && target < 0) {
                target += nums[left++];
            }

            if (target == 0) {
                windowSize = Math.max(windowSize, right - left);
            }
        }

        return windowSize == -1 ? -1 : length - windowSize;
    }
}

2.1.4【1052. 爱生气的书店老板】

1052. 爱生气的书店老板

class Solution {
    public int maxSatisfied(int[] customers, int[] grumpy, int minutes) {
        // 求某个时间段内因为老板生气而被气走的人最多,求出被气走最多的人数
        int length = customers.length;
        int left = 0, right = 0;
        int angryCustomers = 0;
        int goodCustomers = 0;
        for (int i = 0; i < minutes; i++) {
            if (grumpy[i] == 0) {
                goodCustomers += customers[i];
            } else {
                angryCustomers += customers[i];
            }
        }
        int diff = angryCustomers;
        for (int i = minutes; i < length; i++) {
            if (grumpy[i] == 0) {
                goodCustomers += customers[i];
            } else {
                angryCustomers += customers[i];
            }

            // 要减去不在窗口内的顾客
            angryCustomers -= customers[i - minutes] * grumpy[i - minutes];

            diff = Math.max(diff, angryCustomers);
        }

        return goodCustomers + diff;
    }
}

2.1 Minimum Window Substring

题目链接:76. Minimum Window Substring

class Solution {
    public String minWindow(String s, String t) {
        Map<Character, Integer> need = new HashMap<>(), window = new HashMap<>();
        // 统计 t 中字符的数量
        for (char c : t.toCharArray()) {
            need.put(c, need.getOrDefault(c, 0) + 1);
        }
        // 最短子串的开始位置,长度,s 字符串的长度
        int start = 0, lengthWindow = Integer.MAX_VALUE, length = s.length();
        int valid = 0, target = need.size();

        char[] chs = s.toCharArray();
        for (int left = 0, right = 0; right < length; right++) {
            char c = chs[right];
            if (need.containsKey(c)) {
                window.put(c, window.getOrDefault(c, 0) + 1);
                if (Objects.equals(window.get(c), need.get(c))) {
                    valid++;
                }
            }

            
            while (valid == target) {
                if (right - left + 1 < lengthWindow) {
                    start = left;
                    lengthWindow = right - left + 1;
                }

                // 缩小窗口
                char d = chs[left++];
                if (need.containsKey(d)) {
                    if (Objects.equals(window.get(d), need.get(d))) {
                        valid--;
                    }
                    window.put(d, window.get(d) - 1);
                }
            }
        }
        return lengthWindow == Integer.MAX_VALUE ? "" : s.substring(start, start + lengthWindow);
    }
}

2.2 Find All Anagrams in a String

题目链接:438. Find All Anagrams in a String

class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        if (s == null || p == null || s.length() == 0 || p.length() == 0) {
            throw new IllegalArgumentException();
        }
        List<Integer> res = new ArrayList<>();
        int lens = s.length(), lenp = p.length();
        // 如果 s 的长度小于 p 的长度
        if (lens < lenp) return res;

        Map<Character, Integer> need = new HashMap<>(), window = new HashMap<>();
        for (char c : p.toCharArray()) {
            need.put(c, need.getOrDefault(c, 0) + 1);
        }
        int  valid = 0, target = need.size();
        char[] chs = s.toCharArray();
        for (int left = 0, right = 0; right < lens; right++) {
            char c = chs[right];

            window.put(c, window.getOrDefault(c, 0) + 1);
            
            // 当窗口内包含所有 p 中的字符时
            while (window.get(c) > need.getOrDefault(c, 0)) {
                // left 需要移动到 right 的位置,且 window 也要做相应的变更
                char d = chs[left++];
                window.put(d, window.get(d) - 1);
            }
            // 判断一下窗口的宽度,如果与 p 的长度一致才记录 left
            if (right - left + 1 == lenp) res.add(left);
        }

        return res;
    }
}

2.3 Permutation in String

题目链接:567. Permutation in String

class Solution {
    public boolean checkInclusion(String s1, String s2) {
        if (s1 == null || s1.length() == 0 || s2 == null || s2.length() == 0) {
            throw new IllegalArgumentException();
        }

        Map<Character, Integer> need  = new HashMap<>(), window = new HashMap<>();
        for (char c : s1.toCharArray()) {
            need.put(c, need.getOrDefault(c, 0) + 1);
        }
        int len1 = s1.length(), len2 = s2.length();
        int left = 0, right = 0;
        while (right < len2) {
            char c = s2.charAt(right++);
            window.put(c, window.getOrDefault(c, 0) + 1);

            while (window.get(c) > need.getOrDefault(c, 0)) {
                char d = s2.charAt(left++);
                window.put(d, window.get(d) - 1);
            }

            if (right - left == len1) return true;
        }

        return false; 
    }
}

2.4 Longest Substring Without Repeating Characters

题目链接:3. Longest Substring Without Repeating Characters

class Solution {
    public int lengthOfLongestSubstring(String s) {
        // 滑动窗口:左右指针,右指针一直向右边滑动,右指针每到一个新的位置该位置对应字符的统计计数加1,若计数大于1,则窗口向左收缩直至计数值恢复1
        if (s == null) throw new IllegalArgumentException();
        int length = s.length();
        if (length == 0) return 0;

        Map<Character, Integer> window = new HashMap<>();
        int left = 0, right = 0, res = 0;
        while (right < length) {
            char c = s.charAt(right++);
            window.put(c, window.getOrDefault(c, 0) + 1);
            // 如果 right 指向的字符大于1次
            while (window.get(c) > 1) {
                // 左指针开始向右移动,并更新 window 中的字符数量
                char d = s.charAt(left++);
                window.put(d, window.get(d) - 1);
            }

            res = Math.max(res, right - left);
        }

        return res;
    }
}

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值