这里是题目描述:LeetCode-1488.避免洪水泛滥
思路详解:
- 定义如下三个数据结构:
a.Map<Integer, LinkedList<Integer>>
,存储每个湖对应的下雨日期列表,例如1842=><1,21,31>; 1843=><2,22,32>
b.PriorityQueue<Lake>
,这是一个小堆,存储的是湖泊的下一个雨天,谁最近就会排在最上面
c.Set<Integer> fullLacks
,存储哪些湖泊是满的 - 算法步骤如下:
a. 遍历数组rains
,把小雨的日期列表存储到Map<Integer, LinkedList<Integer>> map
中
b. 再次遍历数组rains
,并做如下判断:
i. 如果当前是下雨天
如果当前湖泊已经满了,则返回[]
,表示无解
否则,把当前湖泊的下一个雨天加入到小堆priQueue
,并且把当前的湖泊设置为已满
ii. 如果当前不下雨
如果当前小堆为空(表示目前所有湖泊都是空的),则默认抽湖泊1
否则,从最小堆堆顶返回并抽最近要下雨的湖泊(贪心原则),移除最小堆proQueue
的堆顶,并把当前的湖泊移除自fullLakes
题解代码:
class Solution {
public int[] avoidFlood(int[] rains) {
HashSet<Integer> fullLackSet=new HashSet<>(); //当前有水的湖泊
PriorityQueue<Lack> priQueue=new PriorityQueue<>(); //当前有水的湖泊下一次下雨日期的优先队列
HashMap<Integer, LinkedList<Integer>> lackRainDay=new HashMap<>(); //每个湖泊的下雨日期列表
for(int i=0;i<rains.length;i++) //第一次遍历,构建lackRainDay
{
if(!lackRainDay.containsKey(rains[i]))
{
lackRainDay.put(rains[i],new LinkedList<>());
}
lackRainDay.get(rains[i]).add(i);
}
int[] res=new int[rains.length];
for(int i=0;i<rains.length;i++)
{
if(rains[i]!=0)
{
if(fullLackSet.contains(rains[i])) //发生洪水泛滥
{
return new int[0];
}
else //将当前湖泊加入fullLackSet。如果该湖泊有下一次下雨,将该湖泊编号和下一次下雨日期存入priQueue
{
fullLackSet.add(rains[i]);
lackRainDay.get(rains[i]).removeFirst();
if(!lackRainDay.get(rains[i]).isEmpty())
{
Lack lack=new Lack(rains[i],lackRainDay.get(rains[i]).getFirst());
priQueue.offer(lack);
}
}
res[i]=-1;
}
else //rain[i]==0
{
if(!priQueue.isEmpty())
{
Lack lack=priQueue.remove();
fullLackSet.remove(lack.id);
res[i]=lack.id;
}
else
{
res[i]=1;
}
}
}
return res;
}
}
class Lack implements java.lang.Comparable<Lack>
{
int id;
int nextRainDay;
public Lack(int id, int nextRainDay) {
this.id = id;
this.nextRainDay = nextRainDay;
}
public int compareTo(Lack lack)
{
return this.nextRainDay-lack.nextRainDay;
}
}
时间复杂度:O(nlogn)
空间复杂度:O(n)