目录
题目:
示例:
分析:
代码:
题目:
示例:
分析:
给我们一个一维数组,元素为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;}
};