滑动窗口(三)

Leetcode30. 串联所有单词的子串

题目

Leetcode30. 串联所有单词的子串

解法(滑动窗口)

利用substr函数截取出来的s中截取出一段一段的单词,然后和words中比较是否相等。

  • hash1用来存储words中单词出现的次数
  • left right指针每次移动的步数为wordLen= words[i].size(),也就是单词的长度
  • 边界right + wordLen<= words.size()
  • hash2维护窗口内单词出现次数
  • if(hash1.count(in) && hash2[in] <= hash1[in]) count++;
  • if(hash1.count(out) && hash2[out] <= hash1[out]) count--;

代码

class Solution 
{
public:
    vector<int> findSubstring(string s, vector<string>& words) 
    {
        vector<int> res;
        
        unordered_map<string, int> hash1;//保存words里面单词出现的次数
        for(auto i : words) hash1[i]++;

        int wordLen = words[0].size(), n = words.size();
        for(int i = 0; i < wordLen; i++)
        {
            unordered_map<string, int> hash2;//维护窗口中单词出现的次数
            for(int left = i, right = i, count = 0;  right + wordLen <= s.size(); right += wordLen)
            {
                //进窗口 + 维护count
                string in = s.substr(right, wordLen);
                hash2[in]++;
                if(hash1.count(in) && hash2[in] <= hash1[in]) count++;

                if(right - left + 1 > wordLen * n)//判断
                {
                    //出窗口 + 维护count
                    string out = s.substr(left, wordLen);
                    if(hash1.count(out) && hash2[out] <= hash1[out]) count--;
                    hash2[out]--;
                    left += wordLen;
                }
                //更新结果
                if(n == count) res.push_back(left);
            }
        }
        return res;
    }
};

时间复杂度O(N*M)

Leetcode76. 最小覆盖子串

题目

Leetcode76. 最小覆盖子串

解法(滑动窗口)

  • left = 0, right = 0;
  • 进窗口hash2[in]++
  • 判断check(left, right)-> 出窗口hash2[out]--
  • 更新结果(位置每一题都不同,本题在判断后)

利用count来统计有效字符的种类(在check判断的时候,用来优化)
1. 进窗口之前 当hash2[in] == hash1[in] count++;
2. 出窗口之后 当hash2[out] ==hash1[out] count - - ;
3. 判断时 count == hash1.size();

代码

class Solution 
{
public:
    string minWindow(string s, string t) 
    {
        int hash1[128] = {0};//统计t中每个字母出现的次数
        int kinds = 0;//统计有效字母的种类
        for(auto i : t) if(hash1[i]++ == 0) kinds++;
        
        int hash2[128] = {0};//统计窗口内每个字母出现的次数
        int res = INT_MAX;
        int begin = -1;
        for(int left = 0, right = 0, count = 0; right < s.size(); right++)
        {
            char in = s[right];
            if(++hash2[in] == hash1[in]) count++;//进窗口+维护count
            while(count == kinds)//判断
            {
                if(right - left + 1 < res)//更新结果
                {
                    res = right - left + 1;
                    begin = left;
                }
                char out = s[left++];
                if(hash2[out]-- == hash1[out]) count--;//出窗口+维护count
            }
        }
        return begin == -1? "" : s.substr(begin, res);
    }
}; 

你可能感兴趣的:(算法,算法,c++,滑动窗口)