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

Posted C_YCBX Py_YYDS

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了滑动窗口经典例题之一——438. 找到字符串中所有字母异位词相关的知识,希望对你有一定的参考价值。

题目


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;
    
;

以上是关于滑动窗口经典例题之一——438. 找到字符串中所有字母异位词的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode 438 找到字符串中所有字母异位词[数组 滑动窗口] HERODING的LeetCode之路

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

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

滑动窗口(最大最小值)的经典例题

滑动窗口(最大最小值)的经典例题

滑动窗口(最大最小值)的经典例题