leetcode: 12.17 第二日(滑动窗口)

目录

209.长度最小的子数组

904:水果成篮。

438:找出字符串中的异位词

76: 最小覆盖字串。


209.长度最小的子数组

题目:

给定一个含有 n 个正整数的数组和一个正整数 target 。

示例 1:

输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。

思想:所谓滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果

这其实也是  双指针  的一种。

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int n = nums.size() - 1;
        int k = 0 ;
        int sum = 0 ;
        int maxsum = INT32_MAX ;
        for ( int i = 0 ;i <= n ; i++){
            sum += nums[i] ; 
            while (sum >= target){
                int sublength =( i - k + 1 );
                maxsum =  maxsum > sublength ? sublength : maxsum;
                sum -= nums[k];
                k++;
            }
        }

        return maxsum == INT32_MAX ? 0 : maxsum ;

    }
};

这里有个注意点: 为什么要用  while  而不是 if 。 

相关题目:

904:水果成篮。

题目:

你想要尽可能多地收集水果。然而,农场的主人设定了一些严格的规矩,你必须按照要求采摘水果:

你只有 两个 篮子,并且每个篮子只能装 单一类型 的水果。每个篮子能够装的水果总量没有限制。
你可以选择任意一棵树开始采摘,你必须从 每棵 树(包括开始采摘的树)上 恰好摘一个水果 。采摘的水果应当符合篮子中的水果类型。每采摘一次,你将会向右移动到下一棵树,并继续采摘。
一旦你走到某棵树前,但水果不符合篮子的水果类型,那么就必须停止采摘。
给你一个整数数组 fruits ,返回你可以收集的水果的 最大 数目。

思路:维护left和right,每次取两个数作为基准,right向右滑动 ··如果fruits[right]不是其中的就更新新的数为基准将left直接移动到right前面一格,然后再向前找left相等的最前面的定位left。 ··如果fruits[right]是其中的就更新ans 。438

class Solution {
public:
    int totalFruit(vector<int>& fruits) {
        int left = 0,right = 0,ans = 0;

        int ln = fruits[left],  rn = fruits[right];

        while(right < fruits.size()){
            
            if(fruits[right] == rn || fruits[right] == ln){
                ans = max(ans,right + 1 - left);
                right++;
            }else{
                left = right - 1;
                ln = fruits[left];
                while(left >= 1 && fruits[left - 1] == ln) left--;
                rn = fruits[right];
                ans = max(ans,right + 1 - left);
            }
        }
        return ans;

    }
};

438:找出字符串中的异位词

题目:

给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。

异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。

示例:

输入: s = "cbaebabacd", p = "abc"
输出: [0,6]
解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。

方法一:滑动窗口
思路

根据题目要求,我们需要在字符串 ss 寻找字符串 pp 的异位词。因为字符串 pp 的异位词的长度一定与字符串 pp 的长度相同,所以我们可以在字符串 ss 中构造一个长度为与字符串 pp 的长度相同的滑动窗口,并在滑动中维护窗口中每种字母的数量;当窗口中每种字母的数量与字符串 pp 中每种字母的数量相同时,则说明当前窗口为字符串 pp 的异位词。

自己答案:

错误点:push_back  忘记书写,中间短杆

14~16行代码,为什么要书写?

第14行代码,为什么不能写等于?

第18行代码,如何定义,且为什么 right 可以书写  等于号。

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        vector<int> res;
        if(s.size() < p.size()) return res;

        vector<int> p_count(26);
        vector<int> s_count(26);

        for (int i = 0 ; i <= p.size()-1 ; i++){
            p_count[p[i] - 'a']++;
        }

        for (int j = 0 ; j < p.size()-1 ; j++){
            s_count[s[j] - 'a']++;
        }

        for (int left=0, right=p.size()-1;right<=s.size()-1;left++,right++){
            s_count[s[right] - 'a']++;
            if(s_count == p_count){
                res.push_back(left);
            }
            s_count[s[left] - 'a' ]--;

        }

        return res;
  

    }
};

官方答案:

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        int sLen = s.size(), pLen = p.size();

        if (sLen < pLen) {
            return vector<int>();
        }

        vector<int> ans;
        vector<int> sCount(26);
        vector<int> pCount(26);
        for (int i = 0; i < pLen; ++i) {
            ++sCount[s[i] - 'a'];
            ++pCount[p[i] - 'a'];
        }

        if (sCount == pCount) {
            ans.emplace_back(0);
        }

        for (int i = 0; i < sLen - pLen; ++i) {
            --sCount[s[i] - 'a'];
            ++sCount[s[i + pLen] - 'a'];

            if (sCount == pCount) {
                ans.emplace_back(i + 1);
            }
        }

        return ans;
    }
};


方法二:优化的滑动窗口
思路和算法

在方法一的基础上,我们不再分别统计滑动窗口和字符串 p 中每种字母的数量,而是统计滑动窗口和字符串 p 中每种字母数量的差;并引入变量 {differ} 来记录当前窗口与字符串 p 中数量不同的字母的个数,并在滑动窗口的过程中维护它。

在判断滑动窗口中每种字母的数量与字符串 p 中每种字母的数量是否相同时,只需要判断 {differ} 是否为零即可:

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        int sLen = s.size(), pLen = p.size();

        if (sLen < pLen) {
            return vector<int>();
        }

        vector<int> ans;
        vector<int> count(26);
        for (int i = 0; i < pLen; ++i) {
            ++count[s[i] - 'a'];
            --count[p[i] - 'a'];
        }

        int differ = 0;
        for (int j = 0; j < 26; ++j) {
            if (count[j] != 0) {
                ++differ;
            }
        }

        if (differ == 0) {
            ans.emplace_back(0);
        }

        for (int i = 0; i < sLen - pLen; ++i) {
            if (count[s[i] - 'a'] == 1) {  // 窗口中字母 s[i] 的数量与字符串 p 中的数量从不同变得相同
                --differ;
            } else if (count[s[i] - 'a'] == 0) {  // 窗口中字母 s[i] 的数量与字符串 p 中的数量从相同变得不同
                ++differ;
            }
            --count[s[i] - 'a'];

            if (count[s[i + pLen] - 'a'] == -1) {  // 窗口中字母 s[i+pLen] 的数量与字符串 p 中的数量从不同变得相同
                --differ;
            } else if (count[s[i + pLen] - 'a'] == 0) {  // 窗口中字母 s[i+pLen] 的数量与字符串 p 中的数量从相同变得不同
                ++differ;
            }
            ++count[s[i + pLen] - 'a'];
            
            if (differ == 0) {
                ans.emplace_back(i + 1);
            }
        }

        return ans;
    }
};


76: 最小覆盖字串。

 示例:

输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"
解释:最小覆盖子串 "BANC" 包含来自字符串 t 的 'A'、'B' 和 'C'。

思路:滑动窗口。

class Solution {
public:
    string minWindow(string s, string t) {
        unordered_map<char , int > hs , ht;
        string ans;
        for (int i = 0 ; i < t.size() ; i++) ht[t[i]]++;

        for (int i = 0 , j =0,cnts = 0; j < s.size();j++){
            hs[s[j]]++;
            if(hs[s[j]] <= ht[s[j]]) { cnts++;}
            while (hs[s[i]] > ht[s[i]]){
                hs[s[i]]--;i++;
            }

            if(cnts == t.size() ){
                if (ans.empty() || ans.length() > j-i+1){
                    ans = s.substr(i, j-i+1);
                }
            }
        }
        return ans;
    }
};

没懂之处:第15行,为什么是等于呢?(个人理解,大于等于应该也是合适的,结果显示是合理的。但是原作者,只是书写了等于,不明所以)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值