[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 天选择抽干的湖泊。

如果有多种可行解,请返回它们中的 任意一个 。如果没办法阻止洪水,请返回一个 空的数组 。

请注意,如果你选择抽干一个装满水的湖泊,它会变成一个空的湖泊。但如果你选择抽干一个空的湖泊,那么将无事发生。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/avoid-flood-in-the-city
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

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

  • 如果 rains[i] == 0,说明那一天不下雨,则用 treeset 记录这个晴天的 index
  • 如果 rains[i] 不是 0,则说明那一天某个湖泊会下雨,在结果集里面需要存入 -1,同时,分如下几种情况再讨论
    • 如果 rains[i] 不存在于 hashmap,即某个湖泊还未下过雨,则将这个湖泊的 index 和下雨天的 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 题目总结

posted @ 2020-06-22 14:14  CNoodle  阅读(630)  评论(0编辑  收藏  举报