滑动窗口问题合集

力扣3 无重复字符的最长子串  

public int lengthOfLongestSubstring(String s) {
        HashMap<Character,Integer> map=new HashMap<>();
        int left=0;
        int maxLen=0;
        for(int i=0;i<s.length();i++){
            char c=s.charAt(i);
            if(!map.containsKey(c)){
                map.put(c,i);
                maxLen=Math.max(maxLen,i-left+1);
            }
            else{
                int index=map.get(c);
                if(index>=left){
                    left=index+1;
                    maxLen=Math.max(maxLen,i-index);
                }
                else{
                    maxLen=Math.max(maxLen,i-left+1);
                }
                map.put(c,i);
            }
        }
        return maxLen;
    }
public int lengthOfLongestSubstring(String s) {
        HashMap<Character,Integer> map=new HashMap<>();
        int left=0;
        int maxLen=0;
        for(int i=0;i<s.length();i++){
            char c=s.charAt(i);
            if(!map.containsKey(c)){
                map.put(c,i);
            }
            else{
                int index=map.get(c);
                if(index>=left){
                    left=index+1;
                }
                map.put(c,i);
            }
            maxLen=Math.max(maxLen,i-left+1);
        }
        return maxLen;
    }
public int lengthOfLongestSubstring(String s){
        if(s.length()==0) return 0;
        HashMap<Character,Integer> map=new HashMap<>();
        int left=0;
        int max=0;
        for(int i=0;i<s.length();i++){
            if(map.containsKey(s.charAt(i))){
                //比如 "dvdf" ,碰到第二个 d,那么应该移动 i 到 v 这个字符,因为这样就从窗口里面把第一个 d 略过了
                left=Math.max(left,map.get(s.charAt(i))+1);
            }
            map.put(s.charAt(i),i);
            max=Math.max(max,i-left+1);
        }
        return max;
    }

力扣 76 最小覆盖子串

public String minWindow(String s, String t) {
        if(s==null||s.length()==0||t==null||t.length()==0) return "";
        int[] need=new int[128];
        //need数组中>0表示该字符还需几个,<0表示窗口内该字符多余的数量,=0表示不需要的字符没有出现在窗口里
        for(int i=0;i<t.length();i++){
            need[t.charAt(i)]++;
        }
        int left=0;//窗口左边界
        int right=0;//窗口右边界
        int count=t.length();
        int minSize = Integer.MAX_VALUE;
        int start=0;//最小子串的最左边界
        while(right<s.length()){
            char c=s.charAt(right);
            if(need[c]>0){
                count--;
            }
            need[c]--;
            if(count==0){
                while(left<right&&need[s.charAt(left)]<0){
                    need[s.charAt(left)]++;
                    left++;
                }
                if(right-left+1<minSize){
                    minSize=right-left+1;
                    start=left;
                }
                need[s.charAt(left)]++;
                left++;
                count++;
            }
            right++;
        }
        return minSize==Integer.MAX_VALUE?"":s.substring(start,start+minSize);
    }

剑指offer59 滑动窗口的最大值

遍历数组时的规律: 

 

因此,队列始终是一个降序队列,队首一定是当前窗口最大值。 

每一次窗口向前滑动,是右边界向右移,左边界向右移。右边界是对比数组中下一个数的大小来实现,左边界需要将当前坐标-窗口长度得到的坐标和队首元素进行对比,如果相同,说明已经不在窗口区间内,需要删掉队首元素,以达到窗口右移的效果。

public int[] maxSlidingWindow(int[] nums, int k) {
        //代码分成窗口形成前和窗口形成后
        if(nums.length==0||k==0) return new int[0];
        Deque<Integer> deque=new LinkedList<>();
        int[] res=new int[nums.length-k+1];
        int index=0;
        for(int i=0;i<k;i++){
            while(!deque.isEmpty()&&deque.peekLast()<nums[i]) deque.removeLast();
            deque.addLast(nums[i]);
        }
        res[index++]=deque.peekFirst();
        for(int i=k;i<nums.length;i++){
            if(nums[i-k]==deque.peekFirst()) deque.removeFirst();//左边界右移
            while(!deque.isEmpty()&&deque.peekLast()<nums[i]) deque.removeLast();
            deque.addLast(nums[i]);
            res[index++]=deque.peekFirst();
        }
        return res;
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值