这道题是我点击随机一题之后,随机出来的一道算法题。题目如下:
你的国家有无数个湖泊,所有湖泊一开始都是空的。当第 n 个湖泊下雨前是空的,那么它就会装满水。如果第 n 个湖泊下雨前是 满的 ,这个湖泊会发生 洪水 。你的目标是避免任意一个湖泊发生洪水。
给你一个整数数组 rains ,其中:
rains[i] > 0 表示第 i 天时,第 rains[i] 个湖泊会下雨。
rains[i] == 0 表示第 i 天没有湖泊会下雨,你可以选择 一个 湖泊并 抽干 这个湖泊的水。请返回一个数组 ans ,满足:
ans.length == rains.length
如果 rains[i] > 0 ,那么ans[i] == -1 。
如果 rains[i] == 0 ,ans[i] 是你第 i 天选择抽干的湖泊。如果有多种可行解,请返回它们中的 任意一个 。如果没办法阻止洪水,请返回一个 空的数组 。
请注意,如果你选择抽干一个装满水的湖泊,它会变成一个空的湖泊。但如果你选择抽干一个空的湖泊,那么将无事发生。
解题思路
看完这道题的题目之后,我的想法是在倘若今天的雨不会造成洪水危害,也就是今天要下雨的湖泊在下雨前是空的,那么就不管他。在不下雨的日子里,也不主动去抽水,而是将这些日子用一个数组存起来,在之后遇到将要发生洪水的时候,再从存起来的日子中找,看有没有可以使用的天数,有的话则用来避免洪水发生,没有的话则证明洪水无法避免,返回空数组。
代码
创建数组
let hasWater = new Map();
let hasdone = [];
let ret = new Array(rains.length).fill('');
这里创建了三个变量,第一个是一个map,用于存放下过雨但是未抽水的湖泊,之所以用map是为了方便之后判断这次下雨的湖泊之前是否有着下过雨但没抽水的经历。一个hasdone数组,用于存放能抽水的日子,最后一个ret,则是题目中要求要返回的数组。
遍历rains
当我们遍历数组rains时,倘若rains[i]为0,代表今天不下雨,我们可以将它添加进hasdone数组中。
if(rains[i]==0){
hasdone.push(i);
}
如果rains[i]不等于0,代表今天要下雨,我们可以先将返回的数组ret中对应的位置赋值为-1.
之后通过hasWater.get(rains[i])==undefined进行判断,如果为true,则代表hasWater中没有这个值,也就是说这个湖泊以前未下过雨,我们将湖泊序号和下雨的天数存入hasWater中
if(hasWater.get(rains[i])==undefined){
hasWater.set(rains[i],i);
}
如果为false,则代表这个湖泊曾经下过雨,因此我们需要在存起来的天数中找是否有着能用来抵消上一次雨的。
首先将上一次下雨的时间取出来,存入lastRainDay变量中
let lastRainDay = hasWater.get(rains[i]);
然后看看还有没有能抽水的日子,如果没有的话,返回空数组
if(hasdone.length==0){
return [];
}
如果有的话,看看有没有符合要求的。就是在能抽水的日子中,有没有日期在上一次下雨日期之后的,然后将找到的第一个日子从数组中删除,让返回的数组ret中代表这一天的位置ret[hasdone[j]]赋上值rains[i],也就是这一天要下雨的那个湖泊的代号。将hasWater中的数据更新,日期更新为这一次下雨,相当于用这一天抵消了这一次洪水的危害。之所以要日期在上一次下雨日期之后,是因为在上一次下雨之前的话就没法抵消这次危机了,之所以要用找到的符合要求的第一个抵消,是因为越靠后的能抽水的天数越珍贵,他有能力抵消的天数多余前面的。
for(let j=0;j<hasdone.length;j++){
if(lastRainDay<hasdone[j]){
ret[hasdone[j]] = rains[i]
hasdone.splice(j,1);
hasWater.set(rains[i],i);
break;
}else if(j == hasdone.length-1 && lastRainDay>hasdone[j]){
return [];
}
}
整体代码
var avoidFlood = function(rains) {
let hasWater = new Map();
let hasdone = [];
let ret = new Array(rains.length).fill('');
for(let i=0;i<rains.length;i++){
if(rains[i]==0){
hasdone.push(i);
}else{
ret[i] = -1;
if(hasWater.get(rains[i])==undefined){
hasWater.set(rains[i],i);
}else{
let lastRainDay = hasWater.get(rains[i]);
if(hasdone.length==0){
return [];
}
for(let j=0;j<hasdone.length;j++){
if(lastRainDay<hasdone[j]){
ret[hasdone[j]] = rains[i]
hasdone.splice(j,1);
hasWater.set(rains[i],i);
break;
}else if(j == hasdone.length-1 && lastRainDay>hasdone[j]){
return [];
}
}
}
}
}
for(let i=0;i<ret.length;i++){
if(ret[i]==0){
ret[i] = 1;
}
}
return ret;
};
可以看见在代码最后,加了一个循环
for(let i=0;i<ret.length;i++){
if(ret[i]==0){
ret[i] = 1;
}
}
这个循环的作用是将ret数组中为0的选项赋值为1。之所以会有为0的选项,是因为可以抽水的日子并不一定会用完,虽然题目中没有具体规定,但是在最后提交的时候,不允许我们在这些不需要干活的日子里休息,哪怕并没有什么影响,也要我们对着干涸的一号湖硬抽。。。。。。虽然感觉很无语,但是没办法,不处理不给过,只能加上了。
运行结果
可以看见,我的代码虽然能通过,但是执行用时非常不理想。虽然不理想,但是能力受限,暂时是无法写出时间消耗更低的代码了。那就这样吧。