滑动窗口(java)

滑动窗口

简介

滑动窗口常使用双指针,解决子序列问题,窗口可以整体移动,也可以向右扩张,由双循环转化为单循环降低时间复杂度

代码模板

枚举右边界,即right++: 把右边界的值加入当前计算,不同的题计算逻辑不同 if (满足某条件,左边界需要收缩) 收缩之前更改记录,即把左边界的值从当前记录中去掉 左边界收缩,即left++

案例

209. 长度最小的子数组

题目描述:给定一个含有 n 个正整数的数组和一个正整数 target 。找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

class Solution{
    public int minSubArrayLen(int s, int[] nums) {
        int l = 0, h = 0, sum = 0, min = Integer.MAX_VALUE;
        while (h < nums.length) {
            sum += nums[h++];
            while (sum >= s) {
                min = Math.min(min, h - l);
                sum -= nums[l++];
            }
        }
        return min==Integer.MAX_VALUE?0:min;
    }
}

思路分析:让右指针先累加数组元素直到达到目标值,通过while来移动左指针并且每次都比较最短的子序列

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

题目描述:给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

class Solution {
    public int lengthOfLongestSubstring(String s) {
        Set set = new HashSet();
        int left = 0;
        int right = 0;
        int max = 0;
        for(;right 
  

思路分析:求无重复问题可以用到set集合去重,并且用contains方法判断是否存在重复元素,若存在则首指针后移,将此元素删除,若不存在存入set中尾指针右移,每次比较最长的子串。

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

题目描述:给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。

class Solution {
    public List findAnagrams(String s, String p) {
        List list = new LinkedList<>();
​
        int[] arr1 = new int[26];
        int[] arr2 = new int[26];
​
        for(int i=0;ip.length()){
                arr1[s.charAt(l++)-'a']--;
            }
            if(r-l+1==p.length()){
                if(Arrays.equals(arr1,arr2)){
                    list.add(l);
                }
            }
        }
        return list;
    }
}

思路分析:此题寻找异位词,可以将两个字符串存入数组中,在同一范围内,比较他们字母出现的次数是否相等,若相等则满足条件,滑动窗口的左侧开始移动,将满足条件的数组下标(arr[l])存入集合

567. 字符串的排列

题目描述:给你两个字符串 s1 和 s2 ,写一个函数来判断 s2 是否包含 s1 的排列。如果是,返回 true ;否则,返回 false 。换句话说,s1 的排列之一是 s2 的 子串 。

class Solution {
    public boolean checkInclusion(String s1, String s2) {
        //判断s1的排列之一是s2的子串
        /*
        1、创建两个数组 分别存入
        2、比较出现的次数来判断是否是子串
         */
        int[] arr = new int[26];//s1  子串
        int[] arr2 = new int[26];//s2  要匹配的字符串
​
        for(int i=0;is1.length()){
                arr2[s2.charAt(l++)-'a']--;
            }
            if(r-l+1==s1.length()){
                if (Arrays.equals(arr,arr2)){
                    return true;
                }
            }
        }
        return false;
    }
}

思路分析:这个题和438. 找到字符串中所有字母异位词的思路基本一致,都是比较字符的出现次数来判断是否相等

219. 存在重复元素 II

题目描述:给你一个整数数组 nums 和一个整数 k ,判断数组中是否存在两个 不同的索引 i 和 j ,满足 nums[i] == nums[j] 且 abs(i - j) <= k 。如果存在,返回 true ;否则,返回 false 。

class Solution {
    public boolean containsNearbyDuplicate(int[] nums, int k) {
        int n=nums.length;
        HashSet set=new HashSet();
        for(int i=0;ik){
                set.remove(nums[i-k-1]);
            }
            if(set.contains(nums[i])){
                return true;
            }
            set.add(nums[i]);
        }
        return false;
    }
}

思路分析:set+滑动窗口 当i大于k说明该窗口长度为k+1,所以将首个元素移除,如果窗口长度小于k并且set内存有该元素,说明符合条件

剑指 Offer 59 - I. 滑动窗口的最大值

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        if(nums.length==0||k==0){
            return new int[0];
        }
        int[] res = new int[nums.length - k + 1];
        int index=0;
        MaxQueue maxQueue = new MaxQueue();
        for(int i=0;i queue;
    private Deque deque;
​
    public MaxQueue() {
        queue = new LinkedList<>();
        deque = new LinkedList<>();
    }
​
    public int Max() {
        if (deque.isEmpty()) {
            return -1;
        }
        return deque.peekFirst();
    }
​
    public void push(int val) {
        queue.offer(val);
        while (!deque.isEmpty() && val > deque.peekLast()) {
            deque.pollLast();
        }
        deque.offerLast(val);//在单调队列中永远都是单调递减
    }
​
    public int pop(){
        if(queue.isEmpty()) {
            return -1;
        }else {
            int pop=queue.poll();
            if(pop==deque.peekFirst()){
                deque.pollFirst();
            }
            return pop;
        }
    }
}

思路分析:通过单调队列来维护每个窗口内的最大值,第二个for循环,继续遍历nums后面的剩余元素,i每走一步,就代表窗口向后移动一步,窗口内元素下标就更新一次,然后将队列第一个元素也就是最大的元素输入res,队列内下标代表的元素是按从大到小排列的,如果前一个下标代表元素小于后一个下标代表元素,那就把前一个元素下标移出队列,后一个元素移入队列,这样就保证的单调,

你可能感兴趣的:(java,算法,leetcode)