904.水果成篮、76. 最小覆盖子串(滑动窗口解法)

904. 水果成篮

题目描述:你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组 fruits 表示,其中 fruits[i] 是第 i 棵树上的水果 种类 。

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

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

解答:

采用滑动窗口法,窗口内存放可采摘的果树;起始位置在窗口内的两种果树扩展完毕时进行移动,移动至第二类的开始处;终止位置用于在存在可行解时寻找最优解。

代码思路:首先从当前位置起,寻找第二种果树,找到后终止位置向后扩展寻找最优解,若最优解大于已有的result则进行更新。寻找结束后,起始位置移动至第二种果树的开始处,继续往下寻找,直到寻找结束为止。

代码实现:

class Solution {
public:
    int totalFruit(vector<int>& fruits) {
        int temp, sub1=0, sub2=0, j=0, result=INT_MIN;
        //temp临时储存的可行解值
        //两个sub是两种水果
        //result 最后的结果
        int location = 0;
        for ( int i=0; i<fruits.size();  ) //左滑窗 找到可行解
        {
            i = location;//i指向第二种果树的开始位置
            sub1 = fruits[i]; //记录第一种水果
            for ( int k=i; k<fruits.size(); k++ ) //寻找可以采摘的第二种水果
            {
                if ( fruits[k]!=fruits[i] )//找到
                {
                    sub2 = fruits[k];
                    location = k;//记录第二种果树的开始位置 
                    break;
                }
            }
            while ( fruits[j]==sub1 || fruits[j]==sub2 )//满足采摘的两种水果
            { //在满足可行解前提下扩大又窗口寻找最大的(最优解)
                temp = j - i + 1;//记录当前的长度
                result = temp > result ? temp : result;//寻找最大的解
                j ++; //右边界扩展
                if ( j==fruits.size() ) //右边界到达临界值
                {
                    return result == INT_MIN ? 0 : result;
                    //没有给result赋值就是没有可行解
                }
            } 
        }
        return result; //无关 不会执行到
    }
};

76. 最小覆盖子串

题目描述:

给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。

注意:对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
如果 s 中存在这样的子串,我们保证它是唯一的答案。

解答:采用滑动窗口法。我们在 s 上滑动窗口,通过移动 r 指针不断扩张窗口。当窗口包含 t 全部所需的字符后,如果能收缩,我们就收缩窗口直到得到最小窗口。(来自leetcode官方题解)

此处如果用每个都进行寻找的办法复杂度就太高了,采用了哈希表进行比较。

可以用一个哈希表表示 t中所有的字符以及它们的个数,用一个哈希表动态维护窗口中所有的字符以及它们的个数,如果这个动态表中包含 t 的哈希表中的所有字符,并且对应的个数都不小于 t 的哈希表中各个字符的个数,那么当前的窗口是「可行」的。

注意:这里 t 中可能出现重复的字符,所以我们要记录字符的个数

代码实现:

class Solution {
public:
    string minWindow(string s, string t) {
        if(s.size() < t.size())
            return "";
        //创建hash表存储s中还应出现的字符,hash表中表项等于t中字符 种类
        map<char, int>hash_map;
        //对于t中的字符串,存储至hash表中。已经有了的计数加1,没有的置为1
        for(auto c:t)
            hash_map[c] = hash_map.find(c) != hash_map.end() ? hash_map[c] + 1 : 1;
        int left=0, right=0;//左右边界
        int count=0;//记录已有字符串长度,当其等于t的长度时表示寻找到了一个子串
        int minleft=0, minright=0;
        int minlength=INT32_MAX;
        for (; right < s.size(); right++){
            if (hash_map.find(s[right]) != hash_map.end()){//右边界移动寻找满足count == t.size()
                if (hash_map[s[right]] >0 )
                    count++;
                hash_map[s[right]]--;
            }
            while(count == t.size()){//此时左边界移动,寻找最小的子串
                if (right - left + 1 < minlength){
                    minlength = right - left + 1;
                    minleft = left;
                    minright = right;
                }
                if (hash_map.find(s[left]) != hash_map.end()){//移动时注意处理串中情况
                    if (hash_map[s[left]] >= 0 ){
                        count--;
                    }
                    hash_map[s[left]]++;
                }
                left++;
            }
        }
        if (minlength != INT32_MAX)
            return string(s.begin()+minleft,s.begin()+minright+1);
        else 
            return "";
    }
};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值