滑动窗口相关题目

滑动窗口相关题目

LeetCode 3. 无重复字符的最长子串

题目描述:

给定一个字符串,找出不含有重复字符的最长子串的长度。

示例说明:

给定 "abcabcbb" ,没有重复字符的最长子串是 "abc" ,那么长度就是3。

给定 "bbbbb" ,最长的子串就是 "b" ,长度是1。

给定 "pwwkew" ,最长子串是 "wke" ,长度是3。请注意答案必须是一个子串,"pwke" 是 子序列  而不是子串。

题目分析:

比较容易想到用滑动窗口来解决该问题,因为该问题是一个子串,是一个连续的字符组成,符合窗口问题的描述--连续的某一个部分(在整体中),根据具体问题设计相应的窗口的滑动、调整情况。该题中是找不含重复字母的最长子串的程度,需要判断什么时候出现重复的字母,一旦出现,把前一个时刻的子串长度进行保留即可。(比较去最大值)

具体代码:

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        
        int freq[256]={0};
        int l=0,r=-1;      //注意初始化以及后边的判断条件
        int res=0;
        
        while(l<s.size())
        {
            if(r+1<s.size()&&freq[s[r+1]]==0)
                freq[s[++r]]++;
            else
            {
                res=max(res,r-l+1);   //位置应该出现在出现重复之后(上边的if条件不满足)
                freq[s[l++]]--;
            }
        }
        return res;
    }
};

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

题目描述:

给定一个字符串 s 和一个非空字符串 p,找到 s 中所有是 p 的字母异位词的子串,返回这些子串的起始索引。

字符串只包含小写英文字母,并且字符串 s 和 p 的长度都不超过 20100。

说明:

字母异位词指字母相同,但排列不同的字符串。
不考虑答案输出的顺序

示例说明:

示例 1:

输入:
s: "cbaebabacd" p: "abc"

输出:
[0, 6]

解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的字母异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的字母异位词。
 示例 2:

输入:
s: "abab" p: "ab"

输出:
[0, 1, 2]

解释:
起始索引等于 0 的子串是 "ab", 它是 "ab" 的字母异位词。
起始索引等于 1 的子串是 "ba", 它是 "ab" 的字母异位词。
起始索引等于 2 的子串是 "ab", 它是 "ab" 的字母异位词。

题目分析:

思想同上,主要是感受一下,窗口的感觉。可以结合代码看。

具体代码:

//第一种实现方式,比较直接,易懂
class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        
        //用滑动窗口来做
        vector<int> ss(256,0),pp(256,0),res;
        
        for(int i=0;i<p.size();i++)   //注意位数
        {
            pp[p[i]]++;       //今后不做改变
            ss[s[i]]++;
        }
        
        if(pp==ss)     //两个字符串相等
            res.push_back(0);
            
        for(int i = p.size(); i < s.size(); ++i) 
        {
            ss[s[i]]++;            //新的起点进行查找

            ss[s[i-p.size()]]--;   //前边的进行恢复(--操作)

            if(pp == ss)  
               res.push_back(i-p.size()+1);
        }
        
        return res;
 
    }
};

//第二种实现方式,不容易理解透,比较偏
class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        
        vector<int> res;
        if(p.size()>s.size()||p.size()==0) return res;

        int freq[256]={0};

        for(int i = 0;i<p.size();++i) 
            freq[p[i]]++;

        int l = 0, r = 0;
        int len = p.size();
        
        while(r<s.size()) 
        {
            if(freq[s[r++]]-->=1) 
                len--;

            if(len == 0) res.push_back(l);

            if(r-l== p.size() && freq[s[l++]]++>=0) 
                len++;
        }       
        return res;
    }
};

剑指offer 65. 滑动窗口的最大值

题目描述:

给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值

示例说明:

例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,
他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: 
{[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, 
{2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。

具体代码:(代码上附有详细的解析,这里就不展开讲述了)

class Solution {
public:
     
    //滑动窗口其实就是一个局部区域找最大值,步长为1的从头开始向后运动。
    //最好能提前都确定好输出的尺寸,几卷积之后的尺寸。如果num长x,size=s;则结果尺寸为x-s+1
    //滑动窗口应该是队列,但是什么样的队列能解决---单调的
     
    vector<int> maxInWindows(const vector<int>& num, unsigned int size)
    {
        vector<int> vec;
        if(num.size()<=0 || num.size()<size ||size<=0) return vec;//处理特殊情况
        deque<int> dq;
        //处理前size个数据,因为这个时候不需要输出最大值;
        for(unsigned int i=0;i<size;i++)
        {
 //假如当前的元素比队列队尾的元素大,说明之前加入的这些元素不可能是最大值了。因为当前的这个数字比之前加入队列的更晚
            while(!dq.empty()&&num[i]>=num[dq.back()])
                dq.pop_back();//弹出比当前小的元素下标
            dq.push_back(i);//队尾压入当前下标
        }
        //处理size往后的元素,这时候需要输出滑动窗口的最大值
        for(unsigned int i=size;i<num.size();i++)
        {
            vec.push_back(num[dq.front()]);
            while(!dq.empty()&&num[i]>=num[dq.back()])
                dq.pop_back();
            if(!dq.empty() && dq.front()<=(int)(i-size))//判断队头的下标是否超出size(窗口)大小,如果超过,要删除队头元素
                dq.pop_front();//删除队头元素
            dq.push_back(i);//将当前下标压入队尾,因为可能在未来是最大值
        }
        vec.push_back(num[dq.front()]);//最后还要压入一次
        return vec;
    }
};

LeetCode 76. 最小覆盖子串

题目描述:

给定一个字符串 S 和一个字符串 T,请在 S 中找出包含 T 所有字母的最小子串。

示例说明:

输入: S = "ADOBECODEBANC", T = "ABC"
输出: "BANC"
说明:

如果 S 中不存这样的子串,则返回空字符串 ""。
如果 S 中存在这样的子串,我们保证它是唯一的答案。

注:这道题目可以感受一下,属于比较难的题目。

猜你喜欢

转载自blog.csdn.net/qq_20110551/article/details/81517648