今天給你們帶來的是一道特別特別特別經典的題目接雨水問題,這個問題是不少算法書上面舉例過的題目。雖然是難度題,可是相對來講仍是比較容易理解的,代碼長度也適中,說了這麼多,就一個意思,你們記得打卡這個題目啊,真的是很nice的一道題,下面咱們來看一下題目描述。算法
給定 n 個非負整數表示每一個寬度爲 1 的柱子的高度圖,計算按此排列的柱子,下雨以後能接多少雨水。數組
示例 1:markdown
輸入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
輸出:6
複製代碼
示例 2:ui
輸入:height = [4,2,0,3,2,5]
輸出:9
複製代碼
示例3:spa
輸入:[4,3,2,0,1,1,5]
輸出:13
複製代碼
上面是由數組 [4,3,2,0,1,1,5]表示的高度圖,在這種狀況下,能夠接 13個單位的雨水(見下圖)。3d
看了上面的示例剛開始刷題的同窗可能有些懵逼,那咱們結合圖片來理解一下,咱們就用示例3的例子進行舉例,他的雨水到底表明的是什麼。code
上圖則爲咱們的題目描述,是否是理解了呢?你也能夠這樣理解咱們在地上放置了若干高度的黃色箱子,他們中間有空隙,而後咱們想在他們裏面插入若干藍色箱子,並保證插入以後,這些箱子的左視圖和右視圖都不能看到藍色箱子。orm
好啦題目咱們已經理解了,下面咱們看一下解題思路。作這個這前咱們能夠先去看一下咱們以前作過的另外一道題目每日溫度。這兩道題目的思路差很少,都是利用了單調棧的思想,下面咱們來看一下具體思路吧。索引
這裏咱們也系統的說一下單調棧,單調棧含義就是棧內的元素是單調的,咱們這兩個題目用到的都是遞減棧(相同也能夠),咱們依次將元素壓入棧,若是當前元素小於等於棧頂元素則入棧,若是大於棧頂元素則先將棧頂不斷出棧,直到當前元素小於或等於棧頂元素爲止,而後再將當前元素入棧。就好比下圖的4,想入棧的話則須要2,3出棧以後才能入棧,由於4大於他倆。圖片
咱們瞭解單調棧的含義下面咱們來看一下接雨水問題到底該怎麼作,其實原理也很簡單,咱們經過咱們的例3來進行說明。
首先咱們依次入棧4,3,2,0咱們的數組前四個元素是符合單調棧規則的。可是咱們的第五個1,是大於0的。那咱們就須要0出棧1入棧。可是咱們這樣作是爲了什麼呢?有什麼意義呢?別急咱們來看下圖。
上圖咱們的,4,3,2,0已經入棧了,咱們的另外一個元素爲1,棧頂元素爲0,棧頂下的元素爲2。那麼咱們在這一層接到的雨水數量怎麼算呢?2,0,1這三個元素能夠接住的水爲一個單位(見下圖)這是咱們第一層接到水的數量。
注:能接到水的狀況,確定是中間低兩邊高,這樣才能夠。
由於咱們須要維護一個單調棧,因此咱們則須要將0出棧1入棧,那麼此時棧內元素爲4,3,2,1。下一位元素爲1,咱們入棧,此時棧內元素爲4,3,2,1,1。下一元素爲5,棧頂元素爲1,棧頂的下一元素仍爲1,則須要再下一個元素,爲2,那咱們求當前層接到的水的數量。
咱們是經過2,1,1,5這四個元素求得第二層的接水數爲1*3=3;1是由於min(2-1,5-1)=min(1,4)得來的,你們能夠思考一下木桶效應。裝水的多少,確定是按最短的那個木板來的,因此高度爲1,3的話是由於5的索引爲6,2的索引爲2,他們之間共有三個元素(3,4,5)也就是3個單位。因此爲6-2-1=3。
將1出棧以後,咱們棧頂元素就變成了2,下一元素變成了3,那麼3,2,5這三個元素一樣也能夠接到水。
這是第三層的接水狀況,可以接到4個單位的水,下面咱們繼續出棧2,那麼咱們的4,3,5仍然能夠接到水啊。
這是咱們第四層接水的狀況,一共可以接到5個單位的水,那麼咱們總的接水數加起來,那就是
1+3+4+5=13。你學會了嗎?別急還有動圖咱們,咱們再來深刻理解一哈。
class Solution {
public int trap(int[] height) {
Stack<Integer> stack = new Stack<Integer>();
int water = 0;
//特殊狀況
if(height.length <3){
return 0;
}
for(int i = 0; i < height.length; i++){
while(!stack.isEmpty() && height[i] > height[stack.peek()]){
//棧頂元素
int popnum = stack.pop();
//相同元素的狀況例1,1
while(!stack.isEmpty()&&height[popnum] == height[stack.peek()]){
stack.pop();
}
//計算該層的水的單位
if(!stack.isEmpty()){
int temp = height[stack.peek()];//棧頂元素值
//高
int hig = Math.min(temp-height[popnum],height[i]-height[popnum]);
//寬
int wid = i-stack.peek()-1;
water +=hig * wid;
}
}
//這裏入棧的是索引
stack.push(i);
}
return water;
}
}
複製代碼
你們若是能感受到這個文章寫的很用心的話,能給您帶來一丟丟幫助的話,能麻煩您給這個文章點個贊嗎?這樣我就巨有動力寫下去啦 你們須要更多經典題目的動圖詳解能夠關注公衆號:【袁廚的算法小屋】,更多精選算法題等着你呀,原創不易,感謝觀看
![](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/69051029d30d42f7b0b22d2e2ca3e789~tplv-k3u1fbpfcp-watermark.image)