滑动窗口问题(最长连续无重复子串,最小覆盖子串,找出字母异位词)

对于此类问题 , 我们需要确定一个最大或者最小满足条件的区间。把区间在字符串或者数组上变化移动想象成一个在窗沿滑动的窗口,当滑到满足条件的位置时,这个窗口即为所求区间。

1.无重复字符的最长字串在这里插入图片描述
设置i为滑动窗口的左边界,j为左边界。j向右移动的目的是向区间添加字符,是的区间无重复增长。i的目的是一旦j的元素与子串中的元素重复,i右移直到将重复的元素丢到后面去。
因为要求无重复字串,所以我们用hashset记录窗口内包含的字符。首先使j向右动,hashset检查有无重复字符,如果没有则将s(j)添加进hashset 。如果有重复字符就移动i 去掉重复字符及重复字符之前的字符。 这样维持一个区间(i,j) j-i+1即为无重复字串的长度。
在这里插入图片描述

    public int lengthOfLongestSubstring(String s) {
        int n = s.length();
        int ans = 0, i = 0, j = 0;
        Set<Character> set = new HashSet<>();
        while (i < n && j < n) {
            if (!set.contains(s.charAt(j))) {
                set.add(s.charAt(j++));
                ans = Math.max(ans, set.size());
            } else {
                set.remove(s.charAt(i++));
            }
        }
        return ans;
    }

最小覆盖子串

与上题相似,同样是找具有特定性质的最短或者最长区间,本题的特定性质是“覆盖”,即s的某个子串中包含t中的所有字母。那么快指针 right的作用是向右移动添加字符,直到【left,right】区间内包含T中的所有元素。那么left的作用就是向右移动,在满足“覆盖”的条件下使区间尽可能变短。
重复上述过程,并且记录最小区间的起始大小。
因为题目中没有要求顺序,并且考虑到T字符串中有字符重复的情况,我们用hashmap<character,integer>来存储字符出现的次数。

    public String minWindow(String s, String t) {
        int left=0;
        int right=0;//区间左右边界
        Map<Character,Integer> need=new HashMap<>();//记录t字符中所有字符出现次数
        for (int i=0;i<t.length();i++){
            int count=need.getOrDefault(t.charAt(i),0);
            need.put(t.charAt(i),count+1);
        }
        Map<Character,Integer> windowCount=new HashMap<>();//windowcount记录滑动窗口内字符出现的次数
        int[] ans={s.length()+1,0,0};//记录满足条件子串的长度,起始位置
        int format=0;//记录windowcount与need中字符个数相同的个数
        while (right<s.length()){
            char c=s.charAt(right);
            int count=windowCount.getOrDefault(c,0).intValue();
            windowCount.put(c,count+1);
            if (need.containsKey(c)&&windowCount.get(c).intValue()==need.get(c).intValue())format++;//注意 Interger与Interger之间的比较有坑,不能直接比较。-128-127在缓冲区可以比,超过就不能比了。
            while (left<=right&&need.size()==format){
                c=s.charAt(left);
                if (ans[0]>right-left+1){
                    ans[0]=right-left+1;
                    ans[1]=left;
                    ans[2]=right;
                }
                windowCount.put(c,windowCount.get(c).intValue()-1);
                if (need.containsKey(c)&&windowCount.get(c).intValue()<need.get(c).intValue())format--;
                left++;
            }
            right++;
        }

        return ans[0]==s.length()+1?"":s.substring(ans[1],ans[2]+1);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值