避免洪水氾濫(leetcode1448)

2021-10-07 10:03:23 字數 3259 閱讀 3513

問題描述:

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

示例 1:

輸入:rains = [1,2,3,4]

輸出:[-1,-1,-1,-1]

解釋:第一天後,裝滿水的湖泊包括 [1]

第二天後,裝滿水的湖泊包括 [1,2]

第三天後,裝滿水的湖泊包括 [1,2,3]

第四天後,裝滿水的湖泊包括 [1,2,3,4]

沒有哪一天你可以抽乾任何湖泊的水,也沒有湖泊會發生洪水。

示例 2:

輸入: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] 也是另乙個可行的沒有洪水的方案。

示例 3:

輸入:rains = [1,2,0,1,2]

輸出:解釋:第二天後,裝滿水的湖泊包括 [1,2]。我們可以在第三天抽乾乙個湖泊的水。

但第三天後,湖泊 1 和 2 都會再次下雨,所以不管我們第三天抽乾哪個湖泊的水,另乙個湖泊都會發生洪水。

示例 4:

輸入:rains = [69,0,0,0,69]

輸出:[-1,69,1,1,-1]

解釋:任何形如 [-1,69,x,y,-1], [-1,x,69,y,-1] 或者 [-1,x,y,69,-1] 都是可行的解,其中 1 <= x,y <= 10^9

示例 5:

輸入:rains = [10,20,20]

輸出:解釋:由於湖泊 20 會連續下 2 天的雨,所以沒有沒有辦法阻止洪水。

大體思路:

乙個貪心思路,遇到晴天時,應該優先選擇裡當天之後最近一次再次裝滿水的湖泊抽乾,以示例2為例,

rains = [1,2,0,0,2,1]

第三天是個晴天,發現裡它最近再次裝滿水的湖泊是2號湖泊,所以應該優先抽乾二號湖泊的水。

解法一:直接貪心

使用一set儲存已經裝滿水的湖泊號,遍歷過程中若當天下雨,就判斷set中是否存在該湖泊,若存在則說明該湖泊沒能抽乾,引發渾水;否則將下雨的湖泊號存入set。若當前晴天,就在從當天的下一天開始遍歷,找到第乙個再次下雨的湖泊,並將其從set中刪除。該方法o(n^2),直接超時了...**如下:

class solution 

result[i] = -1;

set.add(rains[i]);

continue;

}result[i] = 1;//隨便抽乙個

for(int j = i + 1; j < rains.length; j++)}}

return result;

}}

解法二:貪心 + 二分

首先使用乙個list儲存所有晴天的日期(從前至後)。使用一map儲存下雨的湖泊號和日期(key = 下雨湖泊號 value = 日期)。

遍歷過程中,若當天下雨,判斷該湖泊之前是否下雨,若下之前亦下過雨,則此時在晴天list中二分查詢乙個距上次下雨之後最近的晴天(大於target值中最小的元素),並在該天對該湖泊放水,若找不到則證明發洪水了,最後更新map;若當天不下雨則將當天日期存入list。時間複雜度o(nlog(n)),實現**如下:

class solution 

result[i] = -1;

if(map.containskey(rains[i]))

int index = find(sunday, pre);

result[sunday.remove(index)] = rains[i];

}map.put(rains[i], i);

}return result;

}public int find(listlist, int target)else

}if(list.get(left) > target)

return right;

}}

解法三:貪心 + 最小堆

解法一中我們知道,遇到晴天時我們應該找到其之後的再次滿水的湖泊,對其放水。因此使用一名為nextrain的陣列儲存下次下雨的時間,nextrain[i] 為rain[i]湖泊下次下雨的日期;使用一map儲存湖泊狀態(是否有水);使用一最小堆儲存下一次下雨時間。

遍歷過程中若當天有雨,則判斷當天下雨的湖泊之前是否有水,有水則說明已經發洪水了,否則將當天nextrain[i]存入最小堆,;遇到晴天時,從最小堆中彈出乙個元素,該元素時裡當天最近的再次下雨的日期,因此對該日期對應的湖泊放水即可。

實現**如下:(時間複雜度:o(nlog(n)))

class solution 

}maphaswater = new hashmap<>();

queueminheap = new priorityqueue<>();

int result = new int[rains.length];

for(int i = 0; i < rains.length; i++)

haswater.put(rains[i], true);

minheap.add(nextrain[i]);

}elseelse}}

return result;

}}

Leetcode1陣列練習

31.next permutation class solution def plusone self,digits list int list int l 1 c 0if len digits 0 return digits cur len digits 1 while cur 1 if digi...

LeetCode 1 兩數之和

給定乙個整數數列,找出其中和為特定值的那兩個數。你可以假設每個輸入都只會有一種答案,同樣的元素不能被重用。示例 給定 nums 2,7,11,15 target 9 因為 nums 0 nums 1 2 7 9 所以返回 0,1 step 1 class solution object def tw...

leetcode 1 兩數之和

1.兩數之和 這道題和程式設計之法上面的題目有以下幾個不同 1 題目所給定的陣列是無序的,程式設計之法裡面是預設有序的 2 要求輸出原陣列的序號,如果用乙個結構體維護陣列下標,那麼需要o n 的空間,顯然不是最好的方法 3 題目中包含負數,之前想用數值直接表示陣列下標,陣列值為原來的真正陣列下標,但...