【力扣每日一题】2023.10.13 避免洪水泛滥

目录

题目:

示例:

分析:

代码:


题目:

示例:

分析:

给我们一个一维数组,元素为0表示对应日期不下雨,非0则表示对应日期对应号的湖泊下雨,下雨之后会导致该湖泊满水,如果湖泊满水之后还下雨,那么就会导致洪水。如果不下雨我们就可以选择一个湖泊抽水,抽水之后对应湖泊就空了。同时,所有湖泊一开始都是空的。

要我们返回一个一维数组,第i个元素表示第i天我们抽取的湖泊号数,如果那天下雨,那么我们无法抽水,给答案置-1。要我们避免发生洪水,可以返回任意抽水方案。

如果我们无论怎么抽水都会导致洪水,那么返回空数组。

我们需要保证在某湖泊下雨之前,这个湖泊是空的,也就是说除非这个湖泊是第一次下雨,否则我们需要在下雨之前把这个湖泊给抽了。

我们能抽水的时候只能是没有下雨的时候,所以没下雨的时候我们就要选择抽哪个湖泊的水了,这该如何选择呢?我们要抽的湖泊是下一个下雨且已经满了的湖泊,也就是这个湖泊已经下过雨了,并且下一个下雨的还是这个湖泊,这样就可以避免洪水了。

所以我们需要记录下过雨的湖泊,使用set或是map都可以很方便地查询某号湖泊是否下过雨,具体选择哪种容器我们接着再分析。

假设我们不知道下一次下雨的是哪个湖泊,那么我们就在没下雨的日期放个“时光机器”,也就是把没下雨的日期记录下来,这次抽水的机会我们先不抽水,等下下次下雨的时候我再“穿越”回合适的日期把这个湖泊的水抽掉。

存放这个“时光机器”也就是索引的容器,我们可以使用vector。

如果某个湖泊下雨了,并且之前下过雨,我们需要“穿越”回去抽水了,现在从存放“时光机器”的容器里我们选择合适的日期穿越回去,最合适的日期就是这个湖泊第一次下雨之后的第一个没雨的日期,我们就挑选出比该湖泊第一次下雨的日期更大的第一个日期,由此可见,我们不仅要存储下雨的湖泊,还需要记录该湖泊下雨时的日期,所以回到刚刚的容器选择问题,存放下过雨的湖泊的容器我们选择map,键值就是下雨的日期。

现在已经分析完毕,我们把之前的分析结果串连起来。

我们用下标遍历题目给出的数组,如果元素为0表示不下雨,我们就把当前下标存入vector中。

如果元素不为0表示有湖泊不下雨,我们就开始操作,如果是第一次下雨我们就将湖泊的号数连同下标(也就是日期)存放进map中,如果不是第一次下雨,那就意味着我们需要“穿越”回去把这个湖泊的水抽走了。

由于我们是按顺序存放日期的,所以我们可以直接遍历vector,找到第一个大于这个湖泊第一次下雨日期的日期,然后将对应日期的答案修改为这个湖泊的号数。如果我们遍历完全部的vector都找不到合适的日期,那么就表明我们无法做到不发生洪水,这时返回空数组即可。

同时不要忘记收尾工作,我们“穿越”回去把湖泊第一次下的雨给抽走了,那么就相当于湖泊下的第二场雨变成了“第一次下的雨”,所以我们还需要更新湖泊下雨的日期,以及把使用过的“时光机器”从容器中移除。

最后返回结果即可。

代码:

class Solution {
public:
    vector<int> avoidFlood(vector<int>& rains) {
        int n=rains.size();
        vector<int>res(n,1);                //默认抽取1号
        vector<int> flag;                   //存储可以抽水的日期
        unordered_map<int,int>m;            //存放湖泊装满水的日期
        for(int i=0;i<n;i++){
            if(rains[i]==0) flag.push_back(i); //如果没下雨,那么可以抽水,记录日期   
            else{
                if(m.find(rains[i])==m.end()) m[rains[i]]=i;    //如果湖泊第一次下雨,记录日期
                else{
                    auto index=flag.begin();            
                    //找到比湖泊装满水的日期之后的第一个可以抽水的日期
                    for(;index!=flag.end();++index){
                        if((*index)>m[rains[i]]){
                            //找到了就回到那天去抽这个湖泊
                            res[(*index)]=rains[i];
                            break;
                        }
                    }
                    //如果找不到,那么发生洪水
                    if(index==flag.end()) return {};
                    //移除这个可以抽水的日期
                    flag.erase(index);
                    //更新装满水的日期
                    m[rains[i]]=i;
                }
                res[i]=-1;
            }
        }
        return res;
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值