- js版本写了个小顶堆来实现最近要抽水的湖泊,但是放到力扣中抛弃了超时了,不知道怎么优化了,但是java版本是不超时的,真奇怪,两个版本的思路是一样的.
- 分别搞了三个容器来装,map容器是将同一个湖泊下雨的时间收集到一起.小顶堆heap用来划分需要抽水的湖泊的优先级,根据时间排序,最近要下雨,肯定最先抽干哪个湖泊,不然就洪水了.set用来存现在哪些湖泊是满水的,如果再次下雨下到满水的湖泊,那就直接洪水了.
js版本:
// leetcode 1488 湖泊问题js版本
// 先准备一个小顶堆用来处理干活(抽干哪个湖泊的优先级)的优先级
class MinHeap {
constructor() {
this.heap = []
}
getParentIndex(i) {
return (i - 1) >> 1
}
getLeftIndex(i) {
return (i * 2) + 1
}
getRightIndex(i) {
return (i * 2) + 2
}
shiftDown(index) {
const leftIndex = this.getLeftIndex(index)
const rightIndex = this.getRightIndex(index)
if(this.heap[leftIndex] && this.heap[leftIndex].nextRain < this.heap[index].nextRain) {
this.swap(leftIndex,index)
this.shiftDown(leftIndex)
}
if(this.heap[rightIndex] && this.heap[rightIndex].nextRain < this.heap[index].nextRain) {
this.swap(rightIndex,index)
this.shiftDown(rightIndex)
}
}
shiftUp(index) {
if(index == 0) return
const parentIndex = this.getParentIndex(index)
if(this.heap[parentIndex].nextRain > this.heap[index].nextRain){
this.swap(parentIndex,index)
this.shiftUp(parentIndex)
}
}
swap(i1,i2) {
const temp = this.heap[i1]
this.heap[i1] = this.heap[i2]
this.heap[i2] = temp
}
insert(value) {
this.heap.push(value)
this.shiftUp(this.heap.length - 1)
}
// 删除堆顶的元素
pop() {
const t = this.heap[0]
if(this.size() == 1) {
this.heap = []
return t
}
this.heap[0] = this.heap.pop()
this.shiftDown(0)
return t
}
// 获取堆顶
peek() {
return this.heap[0]
}
size() {
return this.heap.length
}
}
var avoidFlood = function(rains) {
let n = rains.length
let ans = [] // 没有洪水的返回数组,数组中有值
let invalid = [] // 洪水来了,直接返回空数组
let map = new Map() // 用来记录某个湖泊在哪些天会下雨
for(let i = 0; i < n; i++) {
if(rains[i] != 0) {
// 第i天有湖泊下雨
if(!map.get(rains[i])) {
map.set(rains[i],[])
}
map.get(rains[i]).push(i)
}
}
// 没抽干的湖泊表
// 某个湖泊如果满了,加入到set里
// 某个湖泊被抽干了,从set中剔除
let set = new Set()
// 用小顶堆来分配最先处理哪个湖泊,也就是最先需要干的活
const heap = new MinHeap()
for(let i = 0; i < n; i++) {
console.log('rains',i,rains[i])
console.log('截止上次待抽干的湖泊set',set)
console.log('截止上次待干的活heap',heap.heap)
if(rains[i] != 0) { // 今天下雨,不干活返回ans[ℹ] = -1,但是要准备干活的计划,
if(set.has(rains[i])) {
console.log('rains==>2',i,rains[i])
console.log('set==>',set)
// 该湖泊原本没抽干,这次又下雨,必然洪水,直接返回空数组
return invalid
}
// 放入到没抽干的列表
set.add(rains[i])
// 同时该湖泊在哪些天下雨,最前面的时间可以去除掉了
map.get(rains[i]).shift()
//
if(map.get(rains[i]).length != 0 ) {
// 说明该湖泊后面会下雨,可能会有洪水,我得找个合适的时间事先抽干,不然会发洪水
// 所以添加任务到小顶堆
heap.insert({lake: rains[i],nextRain: map.get(rains[i])[0]})
}
ans[i] = -1 //
}else {
// 今天干活,抽干某个湖泊的水,肯定是先抽干最近要下雨的湖泊,躲避洪水呀
// 看看小顶堆的干活表中有没有活可以干
if(heap.size() == 0) {
// 没有活可干
ans[i] = 1 // 题目规定,无活可干返回1
}else {
let work = heap.pop()
console.log('work',work)
console.log('workset',set)
set.delete(work.lake)
ans[i] = work.lake
console.log('从待抽干的set抽干',set)
console.log('从待干的活中干完一个',heap)
}
}
console.log('----------------------------------')
}
return ans
};
let ans = avoidFlood([1,0,1,0,2,0,2])//[-1,1,-1,1,-1,2,-1]
console.log(ans)
java版本:
package class52;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.PriorityQueue;
public class Problem_1488_AvoidFloodInTheCity {
// rains[i] = j 第i天轮到j号湖泊下雨
// 规定,下雨日,干啥 : -1
// 不下雨日,如果没有湖泊可抽 : 1
public static int[] avoidFlood(int[] rains) {
int n = rains.length;
int[] ans = new int[n];
int[] invalid = new int[0];
// key : 某个湖
// value : 这个湖在哪些位置降雨
// 4 : {3,7,19,21}
// 1 : { 13 }
// 2 : {4, 56}
HashMap<Integer, LinkedList<Integer>> map = new HashMap<>();
for (int i = 0; i < n; i++) {
if (rains[i] != 0) { // 第i天要下雨,rains[i]
// 3天 9号
// 9号 { 3 }
// 9号 {1, 3}
if (!map.containsKey(rains[i])) {
map.put(rains[i], new LinkedList<>());
}
map.get(rains[i]).addLast(i);
}
}
// 没抽干的湖泊表
// 某个湖如果满了,加入到set里
// 某个湖被抽干了,从set中移除
HashSet<Integer> set = new HashSet<>();
// 这个堆的堆顶表示最先处理的湖是哪个
PriorityQueue<Work> heap = new PriorityQueue<>();
for (int i = 0; i < n; i++) { // 0 1 2 3 ...
if (rains[i] != 0) {
if (set.contains(rains[i])) {
return invalid;
}
// 放入到没抽干的表里
set.add(rains[i]);
map.get(rains[i]).pollFirst();
if (!map.get(rains[i]).isEmpty()) {
heap.add(new Work(rains[i], map.get(rains[i]).peekFirst()));
}
// 题目规定
ans[i] = -1;
} else { // 今天干活!
if (heap.isEmpty()) {
ans[i] = 1;// 规定: 没活可干写死1
} else {
Work cur = heap.poll();
set.remove(cur.lake);
ans[i] = cur.lake;
}
}
}
return ans;
}
public static class Work implements Comparable<Work> {
public int lake;
public int nextRain;
public Work(int l, int p) {
lake = l;
nextRain = p;
}
@Override
public int compareTo(Work o) {
return nextRain - o.nextRain;
}
}
}
//[1,0,1,0,2,0,2] [-1,1,-1,1,-1,2,-1]