【貪心】B042_LC_避免洪水氾濫(next 數組 + PQ)

一、Problem

你的國家有無數個湖泊,所有湖泊一開始都是空的。當第 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 天選擇抽乾的湖泊。

如果有多種可行解,請返回它們中的 任意一個 。如果沒辦法阻止洪水,請返回一個 空的數組 。

請注意,如果你選擇抽乾一個裝滿水的湖泊,它會變成一個空的湖泊。但如果你選擇抽乾一個空的湖泊,那麼將無事發生(詳情請看示例 4)。

輸入:rains = [1,2,0,0,2,1]
輸出:[-1,-1,2,1,-1,-1]
解釋:第一天後,裝滿水的湖泊包括 [1]
第二天後,裝滿水的湖泊包括 [1,2]
第三天後,我們抽乾湖泊 2 。所以剩下裝滿水的湖泊包括 [1]
第四天後,我們抽乾湖泊 1 。所以暫時沒有裝滿水的湖泊了。
第五天後,裝滿水的湖泊包括 [2]。
第六天後,裝滿水的湖泊包括 [1,2]。
可以看出,這個方案下不會有洪水發生。同時, [-1,-1,1,2,-1,-1] 也是另一個可行的沒有洪水的方案。

提示:

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

二、Solution

方法一:貪心

思路

  • 湖的狀態:沒水、滿水、滿水後再下雨(洪災)
  • 決策:對於沒水的湖,選擇抽哪個有水湖的呢?答案是再次最早下雨的的湖,比如在第 3 天之前有已經下過雨的湖,編號爲 [3,4,5]:3 湖將會再次在第 6 天下雨,4 湖將會再次在第 5 天下雨,3 湖將會再次在第 4 天下雨,如果當前已經是第 3 天了,你應該抽乾那一個湖?顯然是 3 湖。

算法

  • 優先級隊列存儲最緊急被拯救的湖的編號 lID、以及該湖下一次下雨的日期 rDay
  • 如果當天不下雨 rains[i] = 0,則抽乾一個最緊急的湖;而如果沒有最緊急的湖,就隨便抽一個。
  • 如果當天下雨 rains[i] != 0,則將該湖的下一次下雨的日期以及湖編號添加到優先隊列找那個;
  • 特判:如果當前日期爲 ii,且有最緊急的湖在第 ii 天(再次下雨的日期)下雨,那麼該湖無法拯救,則會導致洪災,返回空數組。
class Solution {
    public int[] avoidFlood(int[] rs) {
    	int n = rs.length, INF = n+1, whatEver = 1, next[] = new int[n];	//next記錄
    	Map<Integer, Integer> mp = new HashMap<>();
    	for (int i = n-1; i >= 0; i--) {
    		next[i] = mp.getOrDefault(rs[i], INF);
    		mp.put(rs[i], i);			//該湖最後下一次下雨的日期
    	}

    	int ans[] = new int[n];
    	Queue<Info> pq = new PriorityQueue<>((e1, e2) -> e1.rDay - e2.rDay);
    	Arrays.fill(ans, -1);
    	
    	for (int i = 0; i < n; i++) {
    		if (rs[i] == 0) {
    			if (!pq.isEmpty()) ans[i] = pq.poll().lID;
    			else 			   ans[i] = whatEver;
    		} else {
    			pq.add(new Info(rs[i], next[i]));
    		}
    		if (!pq.isEmpty() && pq.peek().rDay <= i)
    			return new int[0];
    	}
    	return ans;
    }
    class Info {
    	int lID, rDay;
    	Info(int lID, int rDay) { this.lID = lID; this.rDay = rDay; }
    }
}

複雜度分析

  • 時間複雜度:O(nlogn)O(nlogn)
  • 空間複雜度:O(n)O(n)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章