利用滑动窗口的思想解决字串、子数组问题 lc209、lc3、lc438、lc76问题合集

滑动窗口(Sliding Window)

学过计算机网络的同学对于“滑动窗口”这个名词一定不会陌生,在计网中利用到滑动窗口的思想实现了网络中数据传输的流量控制、差错控制等等…

同样在刷题中,滑动窗口也是一种重要的思想,用来解决字串,子数组的问题。在使用滑动窗口解决问题时,始终会维护两个指针left和right分别指向当前窗口的左边界与右边界,每次移动左指针或者右指针,移动之后判断窗口之内的元素是否满足要求。

什么时候使用滑动窗口?

当题目给出的输入是一个字符串或者一个数组,所求解是该字符串或数组的一部分时,通常你就需要考虑使用滑动窗口来解决该问题.

下面给出几个leectcode中关于滑动窗口的例题,我只给出了代码实现,想要看题目以及详细解答的可以移步leetcode

lc209 长度最小的子数组 (mid)

长度最小的子数组

//209
public class 长度最小的子数组 {
    //利用滑动窗口的思想寻找符合要求的子数组
    //当数组中的元素值的和小于target的时候移动右指针,容纳更多数入数组
    //当数组中的元素值的和大于target的时候移动左指针,减少数组中元素的个数,缩短数组的长度
    public int minSubArrayLen(int target, int[] nums){
        int left=0;
        int right=-1;
        int minLength=nums.length+1;
        int currLength=nums.length+1;
        int sum=0;
        while(left<nums.length){
            if(right<(nums.length-1) && sum<target){
                sum+=nums[++right];
            }else{
                sum-=nums[left++];
            }
            if(sum>=target){
                currLength=right-left+1;
                minLength=currLength<minLength ? currLength : minLength;
            }
        }

        if(minLength==(nums.length+1))
            return -1;
        return minLength;
    }
}

lc3 无重复字符的最长子串 (mid)

无重复字符的最长子串

public class 无重复字符的最长字串 {
    public int lengthOfLongestSubstring(String s) {
        int left=0;
        int right=-1;
        int maxLen=0;
        Map<Character,Integer> map=new HashMap<>();

        while(right<s.length()-1){
            if(!map.containsKey(s.charAt(right+1))){
                map.put(s.charAt(right+1),1);
                right++;
                int len=right-left+1;
                if(maxLen<len)
                    maxLen=len;
            }else{
                map.remove(s.charAt(left));
                left++;
            }
        }
        return maxLen;
    }
}

lc438 找到字符串中所有字母异位词 (mid)

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

public class 找到字符串中所有字母异位词 {
    public List<Integer> findAnagrams(String s, String p) {
        List<Integer> list=new LinkedList<>();
        if(s.length()<p.length())
            return list;
        int left=0;
        int right=p.length()-1;

        while(right<s.length()){
            if(isAnagrams(s.substring(left,right+1),p)){
                list.add(left);
            }
            left++;
            right++;
        }
        return list;
    }

    public boolean isAnagrams(String a,String b){
        int[] arrA=new int[26];
        int[] arrB=new int[26];
        for(int i=0;i<a.length();i++){
            int index=a.charAt(i)-'a';
            arrA[index]++;
        }
        for(int i=0;i<b.length();i++){
            int index=b.charAt(i)-'a';
            arrB[index]++;
        }
        if(Arrays.equals(arrA,arrB))
            return true;
        else
            return false;
    }
}

lc76 最小覆盖子串 (hard)

最小覆盖子串

class Solution {
    public String minWindow(String s, String t) {
        if(s.length()<t.length())
            return "";

        int sLen=s.length();
        int tLen=t.length();
        int minLen=sLen+1;              //设置一个不可能到达的初始值
        int resLeft=0;
        int resRight=0;
        int[] need=new int[128];        //记录还需要哪些字母才能覆盖t字符串,数值>0时表示还需要,<0时表示有多余的该字母
        int needCount=tLen;             //记录所需字母的总数
        int left=0;                     //字串范围[left,right)
        int right=0;

        //通过遍历字符串t,初始化need数组
        for(int i=0;i<tLen;i++){
            need[t.charAt(i)]++;
        }
        while(right<sLen){      //循环结束条件,直到右指针走到s末尾
            //当needCount大于0时移动右指针
            while(needCount>0 && right<sLen){
                if(need[s.charAt(right)]>0)     //仅对t中需要的字母更新needCount
                    needCount--;
                need[s.charAt(right)]--;
                right++;
            }
            if(needCount!=0)        //右指针走到最后的时候都没找到满足条件的字串,则直接退出循环
                break;
            //当needCount等于0时移动左指针,寻找满足要求最短的字串
            while(needCount==0 && left<right){
                need[s.charAt(left)]++;
                if(need[s.charAt(left)]>0)
                    needCount++;
                left++;
            }
            int currLen=right-left+1;
            if(currLen<minLen){
                minLen=currLen;
                resLeft=left-1;
                resRight=right-1;
            }
        }

        if(minLen==sLen+1)
            return "";
        return s.substring(resLeft,resRight+1);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值