【算法练习】滑动窗口

长度最小的子数组

在这里插入图片描述

算法思路
利用单调性,使用“同向双指针”
1.left = 0,right = 0
2.进窗口
3.判断
出窗口

代码

public class Solution {
    
    
    public int minSubArrayLen(int target, int[] nums) {
    
    
        int n = nums.length, sum = 0, len = Integer.MAX_VALUE;
        for (int left = 0, right = 0; right < n; right++) {
    
    
            sum += nums[right]; // 进窗口
            while (sum >= target) {
    
     // 判断
                len = Math.min(len, right - left + 1); // 更新结果
                sum -= nums[left++]; // 出窗口
            }
        }
        return len == Integer.MAX_VALUE ? 0 : len;
    }
}

无重复字符的最长子串

在这里插入图片描述
代码

public int lengthOfLongestSubstring(String ss) {
    
    
        char[] s = ss.toCharArray();

        int[] hash = new int[128]; // 用数组模拟哈希表
        int left = 0, right = 0, n = ss.length();
        int ret = 0;
        while (right < n) {
    
    
            hash[s[right]]++; // 进入窗口
            while (hash[s[right]] > 1) {
    
     // 判断
                hash[s[left++]]--; // 出窗口
            }
            ret = Math.max(ret, right - left + 1); // 更新结果
            right++; // 让下一个字符进入窗口
        }
        return ret;
    }

最大连续1的个数III

在这里插入图片描述

算法原理:
转化:找出最长的子数组,0的个数不超过K个
1.left = 0,right = 0
2.进窗口
3.判断
出窗口
更新结果

代码

class Solution {
    
    
    public int longestOnes(int[] nums, int k) {
    
    
        int ret = 0;
        for (int left = 0, right = 0, zero = 0; right < nums.length; right++) {
    
    
            if (nums[right] == 0) zero++; // 进窗口
            while (zero > k)  //判断
                if (nums[left++] == 0) zero--; // 出窗口
            ret = Math.max(ret, right - left + 1);
        }
        return ret;
    }
}

将x减到0的最小操作数

在这里插入图片描述

算法原理
转化:找出最长的子数组的长度,所有元素的和正好等于sum-x
滑动窗口:
1.left = 0, right = 0
2.进窗口
3.判断
出窗口
更新结果

代码

class Solution {
    
    
    public int minOperations(int[] nums, int x) {
    
    
        int sum = 0;
        for (int a : nums) {
    
    
            sum += a;
        }
        int target = sum - x;
        // 处理细节
        if (target < 0) return -1;
        int ret = -1;
        for (int left = 0, right = 0, tmp = 0; right < nums.length; right++) {
    
    
            tmp += nums[right]; // 进窗口
            while (tmp > target) // 判断
                tmp -= nums[left++]; // 出窗口
            if (tmp == target)
                ret = Math.max(ret, right - left + 1);// 更新结果
        }
        if (ret == -1) return ret;
        else return nums.length - ret;
    }
}

水果成篮

在这里插入图片描述
代码

class Solution {
    
    
    public int totalFruit(int[] fruits) {
    
    
        int ret = 0;
        int n = fruits.length;
        int[] hash = new int[n + 1]; // 统计窗口内水果的种类
        for (int left = 0, right = 0,kinds = 0; right < n; right++) {
    
    
            int in = fruits[right];
            if (hash[in] == 0) kinds++; // 维护水果种类
            hash[in]++; // 进窗口
            while (kinds > 2) {
    
     // 判断
                int out = fruits[left];
                hash[out]--;// 出窗口
                if (hash[out] == 0) kinds--;
                left++;
            }
            // 更新结果
            ret = Math.max(ret, right - left + 1);
        }
        return ret;
    }
}

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

在这里插入图片描述
代码

class Solution {
    
    
    public List<Integer> findAnagrams(String ss, String pp) {
    
    
        List<Integer> ret = new ArrayList<>();
        char[] s = ss.toCharArray();
        char[] p = pp.toCharArray();

        int[] hash1 = new int[26]; // 统计字符串 p中每一个字符出现的个数
        for (char ch : p) hash1[ch - 'a']++;
        int[] hash2 = new int[26]; // 统计窗口中每个字符出现的个数
        int m = p.length;
        for (int left = 0, right = 0, count = 0; right < s.length; right++) {
    
    
            char in = s[right];
            if (++hash2[in - 'a'] <= hash1[in - 'a']) count++; // 进窗口  + 维护 count
            if (right - left + 1 > m) {
    
    // 判断
                char out = s[left++];
                if (hash2[out - 'a']-- <= hash1[out - 'a']) count--; // 出窗口 + 维护 count
            }
            // 更新结果
            if (count == m) ret.add(left);
        }
        return ret;
    }
}

串联所有单词的子串

在这里插入图片描述
代码

class Solution {
    
    
    public List<Integer> findSubstring(String s, String[] words) {
    
    
        List<Integer> ret = new ArrayList<>();
        Map<String, Integer> hash1 = new HashMap<>(); // 保存字典中所有单词的频次
        for (String str : words) hash1.put(str, hash1.getOrDefault(str, 0) + 1);

        int len = words[0].length();// 每个单词的长度
        int m = words.length;
        for (int i = 0; i < len; i++) {
    
     // 执行次数
            Map<String, Integer> hash2 = new HashMap<>(); // 保存窗口内单词的频次
            for (int left = i, right = i, count = 0; right + len <= s.length(); right += len) {
    
    
                // 进窗口 + 维护count
                String in = s.substring(right, right + len);
                hash2.put(in, hash2.getOrDefault(in, 0) + 1);
                if (hash2.get(in) <= hash1.getOrDefault(in, 0)) count++;
                //判断
                if (right - left + 1 > len * m) {
    
    
                    // 出窗口 + 维护count
                    String out = s.substring(left, left + len);
                    if (hash2.get(out) <= hash1.getOrDefault(out, 0)) count--;
                    hash2.put(out, hash2.get(out) - 1);
                    left += len;
                }
                // 更新结果
                if (count == m) ret.add(left);
            }
        }
        return ret;
    }
}

最小覆盖子串

在这里插入图片描述
代码

class Solution {
    
    
    public String minWindow(String ss, String tt) {
    
    
        char[] s = ss.toCharArray();
        char[] t = tt.toCharArray();

        int[] hash1 = new int[128]; // 统计字符串t中字符的频次
        int kinds = 0; // 字符串t中,又多少种字符
        for (char ch : t)
            if (hash1[ch]++ == 0) kinds++;
        int[] hash2 = new int[128]; // 统计窗口中字符的频次
        int minLen = Integer.MAX_VALUE, begin = -1;
        for (int left = 0, right = 0, count = 0; right < s.length; right++) {
    
    
            char in = s[right];
            if (++hash2[in] == hash1[in]) count++; // 进窗口 + 维护 count
            while (kinds == count) {
    
     // 判断
                // 更新结果
                if (right - left + 1 < minLen) {
    
    
                    begin = left;
                    minLen = right - left + 1;
                }
                char out = s[left++];
                if (hash2[out]-- == hash1[out]) count--; // 出窗口 + 维护 count
            }
        }
        if (begin == -1) return new String();
        else return ss.substring(begin, begin + minLen);
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_61341342/article/details/131747166