滑动窗口经典例题之一——438. 找到字符串中所有字母异位词

本文解析了滑动窗口在解决LeetCode上常见问题如字母异位词查找的通用方法,包括如何使用unordered_map跟踪字符需求、窗口状态管理和收缩条件的应用。通过实例代码展示了如何用相同套路应对不同场景,如子序列问题的最小覆盖子串和子串问题的字母异位词搜索。
摘要由CSDN通过智能技术生成

题目


OJ平台

题目解析

一般滑动窗口问题也不多,LeetCode上能列举出来的例题似乎就这么多:
最小覆盖子串

字符串排列

(今天这题)找所有字母异位词

最长无重复子串

而这些题的解题代码和思路几乎没有太大区别,就是以下这个套路:

void slidingWindow(string s,string t){
unordered_map<char,int> need,window;
	for(char c:t)need[c]++;//更新需要的字符情况

int left = 0,right = 0;
int valid = 0;
while(right < s.size()){
	char c = s[right++];//右移窗口
	/**对窗口内数据的一系列更新**/
	...... //一般来说是根据need更新valid和window窗口
	
	/**判断左窗口是否要收缩**/
	*这里的收缩条件是重点
	一般来说为以下两种收缩条件:
	1.当窗口的长度大于等于答案需要的更新长度时。
		对应:right-left >= t.size()
	2.当窗口中已经包含了所有需要的字符时。
		对应:valid >= need.size()
	while(收缩条件){
	1.进行是否是答案的判断并更新答案。

	2.把左边的字符依次移出窗口,
	如果该字符对valid产生影响则valid--}
}
}
  • 这里的收缩条件是重点!

一般来说为以下两种收缩条件:
1. 当窗口的长度大于等于答案需要的更新长度时。
对应:right-left >= t.size() 一般用于答案为子串的情况。
2. 当窗口中已经包含了所有需要的字符时。
对应:valid >= need.size() 一般用于答案为子序列的情况。

  • 当然还有其他多种收缩条件的情况,这个当然还得视情况而定(比如最长无重复子串的收缩条件应该为字符出现1次以上开始进行收缩

代码对比:

最小覆盖子串(子序列问题的滑动窗口)

class Solution {
public:
    string minWindow(string s, string t) {
        unordered_map<char,int>need,window;
        //更新need
        for(char c:t)need[c]++;
        int left = 0,right = 0;
        //valid用于记录是否达到有效窗口处
        int valid = 0;
        //用于记录更新答案的相关信息
        int start = 0,len = INT_MAX;
        int size = s.size();
        int size_n = need.size();
        while(right<size){
            //c是将移入窗口的字符
            char c = s[right];
            //右移窗口
            right++;
            //进行窗口内数据一系列更新
            if(need.count(c)){
                window[c]++;
                //表示该类字符已经被窗口包括
                if(window[c]==need[c])
                    valid++;
            }
            //判断左窗口是否要收缩
            while(valid==size_n){
                //更新最小覆盖子串
                if(right-left<len){
                    start = left;
                    len = right - left;
                }//d是将移出窗口的字符
                char d = s[left];
                //左移窗口
                left++;
                //进行窗口内数据的更新
                if(need.count(d)){
                    if(window[d]==need[d])
                        valid--;
                    window[d]--;
                }
            }
        }
        return len == INT_MAX?"":s.substr(start,len);
    }
};

找所有字母异位词(子串问题的滑动窗口)

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        int need[26]{0};    //p串需要的字符数目表
        int count[26]{0};   //count计算当前窗口内已经记录的字符
        int needSize = 0;   //needSize为需要的不同字符情况
        for (auto ch:p) {
            need[ch - 'a']++;
            if (need[ch - 'a'] == 1)
                needSize++;
        };
        int l, r;           //左右指针
        l = r = 0;
        int sz = s.size();
        int valid = 0;      //记录有效的字符情况
        vector<int> res;
        while (r < sz) {
            char ch = s[r++];
            if (need[ch - 'a']) {  //如果为所需的字符才将count++
                count[ch - 'a']++;
                if (need[ch - 'a'] == count[ch - 'a'])
                    valid++;       //如果此时这个字符已经达到要求的数目,则valid++
            }
            /*收缩窗口*/
            while (r-l >= p.size()) {
                if (valid == needSize)//更新答案的又一限定条件:字符串长度相等
                    res.push_back(l);
                char t = s[l++];    //窗口左移
                if (need[t - 'a']) {
                    if (count[t - 'a'] == need[t - 'a'])
                        valid--;    //去字符过程中注意判断valid已经不符
                    count[t - 'a']--;
                }
            }
        }
        return res;
    }
};

解题代码

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        int need[26]{0};    //p串需要的字符数目表
        int count[26]{0};   //count计算当前窗口内已经记录的字符
        int needSize = 0;   //needSize为需要的不同字符情况
        for (auto ch:p) {
            need[ch - 'a']++;
            if (need[ch - 'a'] == 1)
                needSize++;
        };
        int l, r;           //左右指针
        l = r = 0;
        int sz = s.size();
        int valid = 0;      //记录有效的字符情况
        vector<int> res;
        while (r < sz) {
            char ch = s[r++];
            if (need[ch - 'a']) {  //如果为所需的字符才将count++
                count[ch - 'a']++;
                if (need[ch - 'a'] == count[ch - 'a'])
                    valid++;       //如果此时这个字符已经达到要求的数目,则valid++
            }
            /*收缩窗口*/
            while (r-l >= p.size()) {
                if (valid == needSize)//更新答案的又一限定条件:字符串长度相等
                    res.push_back(l);
                char t = s[l++];    //窗口左移
                if (need[t - 'a']) {
                    if (count[t - 'a'] == need[t - 'a'])
                        valid--;    //去字符过程中注意判断valid已经不符
                    count[t - 'a']--;
                }
            }
        }
        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值