题目
原题链接
你的国家有无数个湖泊,所有湖泊一开始都是空的。当第 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 天选择抽干的湖泊。
如果有多种可行解,请返回它们中的 任意一个 。如果没办法阻止洪水,请返回一个 空的数组 。
思路
1.构造一个和数组rains
长度相同的结果数组 ans
;
2.使用HashMap
存储当前时间已满的湖泊,key
为湖泊编号,value
为下满该湖泊的时间;
3.使用queue
存储未下雨的天数;
4.循环遍历rains数组:
5.如果当天不下雨,则记录至queue
6.如果当天下雨,且该湖泊已满,先将ans数组对应位置设为-1,,然后从queue
中取出 该湖泊被下满之后的第一个位置,
将ans数组的该天设置为该湖泊的编号;map中的记录修正为当前时间;如果遍历完了整
个队列找不到符合条件的不下雨时间,则返回一个空数组,函数结束。
7.如果当天下雨,该湖泊未满,先将ans数组对应位置设为-1,然后将湖泊编号和时间存入map
。
8.循环结束。
9.如果queue中仍有剩余元素,表示多余的不下雨的日子,根据题意将对应ans对应位置都设为1即可。
10.返回ans数组。
解析
主要比较复杂的部分在第六步。翻译成白话就是:遇到一天(比如第N天)下雨的,且要下雨的那个湖泊当前是满的。那么就需要往前推,找到这个湖泊被下满之后的不下雨的第一天,在那天把这个湖泊抽干,以应对第N天的雨水。那么到了第N天之后,这个湖泊其实还是满的,下满的时间也更新到了第N天。
代码
public int[] avoidFlood(int[] rains) {
HashMap<Integer, Integer> map = new HashMap<>();
LinkedList<Integer> queue = new LinkedList<>();
int[] ans = new int[rains.length];
for (int i = 0; i< rains.length;i++) {
// 当天不下雨,在队列中记录时间
if (rains[i] == 0) {
queue.add(i);
} else {
// 当天下雨,且该池子已满,需提前抽空
if (map.containsKey(rains[i])) {
boolean flag = false;
for(int j = 0;j < queue.size(); j++){
if (queue.get(j) > map.get(rains[i])) {
ans[i] = -1;
ans[queue.get(j)] = rains[i];
map.put(rains[i],i);
queue.remove(j);
flag = true;
break;
} else {
continue;
}
}
if(!flag) return new int[0];
} else {
// 当天下雨,且池子当前未满
ans[i] = -1;
map.put(rains[i],i);
}
}
}
// 剩余的不下雨的日子,都抽1号湖
if (!queue.isEmpty()) {
for (Iterator<Integer> iter=queue.iterator();iter.hasNext();) {
ans[iter.next()] = 1;
}
}
return ans;
}