滑动窗口:

滑动窗口:

/* 滑动窗口算法框架 */
void slidingWindow(string s, string t) {
	//自己创建两个有映射关系的数组
    //HashMap<Character,Integer> needs = new HashMap<>();
    //HashMap<Character,Integer> windows = new HashMap<>();
    //可以选择性讲s和t转换成字符串
    //,会方便一些,读取好像也会快一点
    char[] str1=s.toCharArray();
    char[] str2=t.toCharArray();
    //保存对应字母的个数
    int[] sArr=new int[128];
    int[] tArr=new int[128];
    //更新窗口
    for (char c : t) str2[c]++;
    
    int left = 0, right = 0;
    int valid = 0; 
    while (right < s.size()) {
        // c 是将移入窗口的字符
        char c = s[right];
        // 右移窗口
        right++;
        // 进行窗口内数据的一系列更新
        ...

        // 判断左侧窗口是否要收缩
        while (window needs shrink) {
            // d 是将移出窗口的字符
            char d = s[left];
            // 左移窗口
            left++;
            // 进行窗口内数据的一系列更新
            ...
        }
    }
}

unordered_map就是哈希表(字典),它的一个方法count(key)相当于 Java 的containsKey(key)可以判断键 key 是否存在。

可以使用方括号访问键对应的值map[key]。需要注意的是,如果该key不存在,C++ 会自动创建这个 key,并把map[key]赋值为 0。

所以代码中多次出现的map[key]++相当于 Java 的map.put(key, map.getOrDefault(key, 0) + 1)

例题:

一、LeetCode 76 题,Minimum Window Substring,难度 Hard

换句话说,第一个字符串的排列之一是第二个字符串的子串。


滑动窗口算法的思路是这样

***1、***我们在字符串S中使用双指针中的左右指针技巧,初始化left = right = 0把索引左闭右开区间[left, right)称为一个「窗口」

***2、***我们先不断地增加right指针扩大窗口[left, right),直到窗口中的字符串符合要求(包含了T中的所有字符)。

***3、***此时,我们停止增加right,转而不断增加left指针缩小窗口[left, right),直到窗口中的字符串不再符合要求(不包含T中的所有字符了)。同时,每次增加left,我们都要更新一轮结果。

***4、***重复第 2 和第 3 步,直到right到达字符串S的尽头。

初始状态:

img

增加right,直到窗口[left, right)包含了T中所有字符:

img

现在开始增加left,缩小窗口[left, right)

img

直到窗口中的字符串不再符合要求,left不再继续移动。

img

代码如下:
   public static String minWindow(String s, String t){
   char[] str1=s.toCharArray();
   char[] str2=t.toCharArray();
   int[] sArr=new int[128];
   int[] tArr=new int[128];
   //初始化
   int valid=0;
   for (int i = 0; i < t.length(); i++) {
        tArr[str2[i]]++;
        if(tArr[str2[i]]==1){
            valid++;
        }
    }
    int left=0,right=0;
    int count=0;
    int start=0;//保存结果
    int len= Integer.MAX_VALUE;
    while(right<str1.length){
        char ch=str1[right];
        right++;
        if(tArr[ch]!=0){//包含
            sArr[ch]++;
            if(sArr[ch]==tArr[ch]){//相同元素且个数相同
                count++;
            }
        }
        while (valid==count){
            if(right-left<len){//更新结果
                len=right-left;
                start=left;
            }
            char temp=str1[left];
            left++;
            if(tArr[temp]!=0){//同时移动左边界,到窗口不满足条件!
                if(sArr[temp]==tArr[temp]){
                    count--;
                }
                sArr[temp]--;
            }
        }
    }
   return 		    		
  len==Integer.MAX_VALUE?"":s.substring(start,start+len);
}

二、找所有字母异位词

这是 LeetCode 第 438 题,Find All Anagrams in a String,难度 Medium:

img

相当于,输入一个串S,一个串T,找到S中所有T的排列,返回它们的起始索引

跟寻找字符串的排列一样,只是找到一个合法异位词(排列)之后将起始索引加入res即可。

代码如下:
public static boolean checkInclusion(String s1, String s2) {
        if(s1.length()>s2.length()){
            return false;
        }
        char[] str1=s1.toCharArray();
        char[] str2=s2.toCharArray();
        //
        int[] sArr=new int[26];//26是因为值包含小写字母
        int[] tArr=new int[26];
        //初始化
        int valid=0;
        for (int i = 0; i < s1.length(); i++) {
            sArr[str1[i]-'a']++;
            if(sArr[str1[i]-'a']==1){
                valid++;//有效的
            }
        }
        int left=0,right=0;
        int count=0;
        //遍历
        while(right<s2.length()){
            int ch=str2[right]-'a';
            right++;
            if(sArr[ch]!=0){//判断是否存在
                tArr[ch]++;
                if(tArr[ch]==sArr[ch]){
                    count++;
                }
            }
            while(right-left>=s1.length()){//超出窗口范围
                if(valid==count){
                    return true;
                }
                int temp=str2[left]-'a';
                left++;
                if(sArr[temp]!=0){
                    if(tArr[temp]==sArr[temp]){
                        count--;
                    }
                    tArr[temp]--;
                }

            }

        }
        return false;
}

使用滑动窗口的题还有等等。。

                    count--;
                }
                tArr[temp]--;
            }

        }

    }
    return false;

}




使用滑动窗口的题还有等等。。

LeetCode 438题、LeetCode 567 题、LeetCode 3 题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值