避免洪水泛滥
难度:
标签:
题目描述
代码结果
运行时间: 113 ms, 内存: 32.4 MB
/*
题目思路:
1. 使用一个哈希集合记录每个湖泊是否装满水。
2. 使用一个优先队列来存储需要抽干的湖泊,并且优先级最高的先被抽干。
3. 遍历rains数组:
- 如果rains[i] > 0,表示湖泊下雨:
- 如果湖泊已经满了,返回空数组表示无法避免洪水。
- 否则,将湖泊标记为满。
- 如果rains[i] == 0,表示可以选择一个湖泊抽干:
- 如果有需要抽干的湖泊,则将其从集合中移除,并标记该湖泊为抽干。
4. 返回结果数组。*/
import java.util.*;
import java.util.stream.*;
public class Solution {
public int[] avoidFlood(int[] rains) {
Map<Integer, Integer> lakeMap = new HashMap<>(); // 记录每个湖泊上次下雨的天数
TreeSet<Integer> dryDays = new TreeSet<>(); // 记录可以抽干的天数
int[] ans = new int[rains.length];
Arrays.fill(ans, -1);
IntStream.range(0, rains.length).forEach(i -> {
if (rains[i] > 0) { // 下雨
if (lakeMap.containsKey(rains[i])) { // 该湖泊已满
Integer dryDay = dryDays.higher(lakeMap.get(rains[i])); // 找到最近的可抽干天数
if (dryDay == null) {
ans[0] = 0; // 标记为无法避免洪水
return;
}
ans[dryDay] = rains[i]; // 在dryDay那天抽干这个湖泊
dryDays.remove(dryDay); // 移除这个抽干的天数
}
lakeMap.put(rains[i], i); // 记录下雨的天数
} else { // 不下雨,可以选择抽干湖泊
dryDays.add(i); // 记录这天可以抽干
ans[i] = 1; // 默认值,稍后会更新
}
});
if (ans[0] == 0) return new int[0]; // 无法避免洪水
dryDays.forEach(day -> ans[day] = 1); // 如果还有未使用的抽干天数,任意选择一个湖泊抽干
return ans;
}
}
解释
方法:
此题解的核心思路是使用散列表(字典)来跟踪当前哪些湖泊已经满了,以及它们最后一次被填满的时间。此外,使用一个双端队列(deque)来记录可以抽水的日子,并在需要时找到最近的、合适的日子来抽水,以避免洪水。遍历输入数组,对于每一天:1) 如果是晴天(rains[i] == 0),记录这一天可以抽水;2) 如果是下雨天(rains[i] > 0),检查该湖泊是否已经满了。如果已满,则需要在之前记录的可以抽水的日子中找到一个合适的日子来抽水;如果找不到合适的日子,直接返回空数组。如果湖泊未满,则标记为已满,并记录其下雨的时间。最后,对于所有未使用的晴天,可以随意抽干任何湖泊(避免特殊情况,通常抽干湖泊1)。
时间复杂度:
O(n)
空间复杂度:
O(n)
代码细节讲解
🦆
在实现中,你是如何确保找到的抽水日子是在该湖泊最后一次下雨之后的?能否详细说明这一逻辑?
▷🦆
题解中提到,如果找不到合适的晴天来抽水就返回空数组。这种情况是如何被触发的?能否举一个具体的例子说明?
▷🦆
为什么在处理剩余的晴天时,选择默认抽干湖泊1,而不是其他湖泊?这里的选择对算法的结果有何影响?
▷