[LeetCode] 1488. Avoid Flood in The City

Your country has an infinite number of lakes. Initially, all the lakes are empty, but when it rains over the nth lake, the nth lake becomes full of water. If it rains over a lake which is full of water, there will be a flood. Your goal is to avoid the flood in any lake.

Given an integer array rains where:

  • rains[i] > 0 means there will be rains over the rains[i] lake.
  • rains[i] == 0 means there are no rains this day and you can choose one lake this day and dry it.

Return an array ans where:

  • ans.length == rains.length
  • ans[i] == -1 if rains[i] > 0.
  • ans[i] is the lake you choose to dry in the ith day if rains[i] == 0.

If there are multiple valid answers return any of them. If it is impossible to avoid flood return an empty array.

Notice that if you chose to dry a full lake, it becomes empty, but if you chose to dry an empty lake, nothing changes. (see example 4)

Example 1:

Input: rains = [1,2,3,4]
Output: [-1,-1,-1,-1]
Explanation: After the first day full lakes are [1]
After the second day full lakes are [1,2]
After the third day full lakes are [1,2,3]
After the fourth day full lakes are [1,2,3,4]
There's no day to dry any lake and there is no flood in any lake.

Example 2:

Input: rains = [1,2,0,0,2,1]
Output: [-1,-1,2,1,-1,-1]
Explanation: After the first day full lakes are [1]
After the second day full lakes are [1,2]
After the third day, we dry lake 2. Full lakes are [1]
After the fourth day, we dry lake 1. There is no full lakes.
After the fifth day, full lakes are [2].
After the sixth day, full lakes are [1,2].
It is easy that this scenario is flood-free. [-1,-1,1,2,-1,-1] is another acceptable scenario.

Example 3:

Input: rains = [1,2,0,1,2]
Output: []
Explanation: After the second day, full lakes are  [1,2]. We have to dry one lake in the third day.
After that, it will rain over lakes [1,2]. It's easy to prove that no matter which lake you choose to dry in the 3rd day, the other one will flood.

Example 4:

Input: rains = [69,0,0,0,69]
Output: [-1,69,1,1,-1]
Explanation: Any solution on one of the forms [-1,69,x,y,-1], [-1,x,69,y,-1] or [-1,x,y,69,-1] is acceptable where 1 <= x,y <= 10^9

Example 5:

Input: rains = [10,20,20]
Output: []
Explanation: It will rain over lake 20 two consecutive days. There is no chance to dry any lake.

Constraints:

  • 1 <= rains.length <= 10^5
  • 0 <= rains[i] <= 10^9

避免洪水泛滥。你的国家有无数个湖泊,所有湖泊一开始都是空的。当第 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 天选择抽干的湖泊。
如果有多种可行解,请返回它们中的 任意一个 。如果没办法阻止洪水,请返回一个 空的数组 。

这个题没有什么特别的思路,我这里提供一个可行的做法,会用到hashmaptreeset。其中hashmap存<下雨的湖泊,下雨天index>,treeset存晴天的index。为什么用treeset而不是hashset存晴天的index是因为treeset可以做到有序,这个到后面很有用。开始遍历input数组

  • 如果rains[i] == 0,说明那一天不下雨,则用treeset记录这个晴天的index
  • 如果rains[i]不是0,则说明那一天某个湖泊会下雨,在结果集里面需要存入-1,同时,分如下几种情况再讨论
    • 如果rains[i]不存在于hashmap,即某个湖泊还未下过雨,则将这个湖泊下雨天的index存入hashmap
    • 如果rains[i]存在于hashmap,说明某个湖泊已经下过雨了,此时需要试着找一下是否有0(不下雨的天)在这个湖泊第一次下雨之后,将rains[i]这个湖泊的水抽干,否则整体就要返回[0]了(说明抗洪失败)。因为treeset存的是晴天的index,所以这个找0的方式是去看treeset是否为空或者treeset.ceiling(day)是否有值返回,若有则找到一个晴天来抽水,若没有则抗洪失败

treeset的ceiling方法是去treeset找一个最小的大于day的元素,也就是去找某个湖泊第一次下雨之后最近的晴天。其余的解释请参考注释。

时间O(n)

空间O(n)

Java实现

 1 class Solution {
 2     public int[] avoidFlood(int[] rains) {
 3         int n = rains.length;
 4         int[] res = new int[n];
 5         // <下雨的湖泊,下雨天index>
 6         Map<Integer, Integer> map = new HashMap<>();
 7         // treeset存不下雨天index
 8         TreeSet<Integer> treeset = new TreeSet<>();
 9         for (int i = 0; i < n; i++) {
10             if (rains[i] != 0) {
11                 res[i] = -1;
12                 // 如果某个湖泊又下雨了
13                 if (map.containsKey(rains[i])) {
14                     // 找到这个湖泊第一次下雨天的index
15                     int day = map.get(rains[i]);
16                     // 如果treeset为空或者在day之后没有不下雨的天数则说明会发洪水
17                     if (treeset.isEmpty() || treeset.ceiling(day) == null) {
18                         return new int[0];
19                     }
20                     // 找到了某一天把水抽干
21                     res[treeset.ceiling(day)] = rains[i];
22                     // 记录当前湖泊最新一次的下雨天index
23                     map.put(rains[i], i);
24                     // 从treeset中去掉已经用掉的不下雨天index
25                     treeset.remove(treeset.ceiling(day));
26                 } else {
27                     map.put(rains[i], i);
28                 }
29             } else {
30                 treeset.add(i);
31             }
32         }
33 
34         // 不下雨的天数全都去抽干第一个水池
35         for (int i = 0; i < n; i++) {
36             if (res[i] == 0) {
37                 res[i] = 1;
38             }
39         }
40         return res;
41     }
42 }

LeetCode 题目总结

猜你喜欢

转载自www.cnblogs.com/cnoodle/p/13176571.html