題目描述:給 n 個非負整數表示的柱形圖,每個柱子寬度為1,計算雨后能存儲多少水。如:
Given [0,1,0,2,1,0,1,3,2,1,2,1], return 6
分析:對每個柱子找到其左右兩邊最高的柱子,則這個柱子能容納的水的體積就是min(max_left, max_right)。
方法一:對每個柱子
從左往右掃描一遍,記錄其左側柱高的最大值
從右往左掃描一遍,記錄其右側柱高的最大值
再從頭到尾掃一遍,累加每個柱子可容納的體積
三次遍歷,時間復雜度O(n),空間復雜度O(n)。
class Solution {
public:
int trap(vector<int>& height) {
int n = height.size();
if (n < 3) return 0;
int mxl[n] = {0}, mxr[n] = {0}; //分別記錄該柱子左右兩側的最高柱子的高度。數組需要顯示初始化為0,否則為隨機值。
for (int i = 1; i < n; i ++) //l 記錄從1 ~ (n - 1) ,r記錄從 0 ~ (n - 2)。兩個過程遍歷方向相反但可在一次遍歷中完成
{
mxl[i] = max(mxl[i - 1], height[i - 1]); //當前柱子左側的最高高度為前一個柱子左側的最高高度與前一個柱子的高度的最大值
mxr[n - 1 - i] = max(mxr[n - i], height[n - i]); //下標為 n - 1 - i 柱子右側的最高高度為其后一個柱子右側的最高高度與后一個柱子的高度的最大值
}
int s = 0;
for (int i = 0; i < n; i++)
{
int ht = min(mxl[i], mxr[i]);
//cout<<mxl[i]<<" "<<mxr[i]<<endl;
//cout<<ht<<endl;
if (ht > height[i]) //若當前柱子左右兩側最高高度的最小值比當前柱子高度高,則該柱上面缺失的部分都是存水的體積
s += ht - height[i];
}
return s;
}
};
方法二:
遍歷一遍找到最高的柱子,該柱子將數組分為兩半
處理左部分
處理右部分
三次遍歷,時間復雜度O(n),空間復雜度O(1)。
class Solution {
public:
int trap(vector<int>& height) {
int mx = 0; //記錄最高柱子的下標
int n = height.size();
for (int i = 0; i < n; i ++)
if (height[i] > height[mx])
mx = i;
int w = 0; //記錄體積
for (int i = 0, lp = 0; i < mx; i ++) //從前往后遍歷左部分,此時右側的最高高度已確定,lp記錄左側的最高高度
{
if (height[i] > lp) //如果左側有更高的柱子,則提高標尺
lp = height[i];
else
w += lp - height[i]; //較低的柱子的上面是儲水的體積
}
for (int i = n - 1, rp = 0; i > mx; i --) //從后往前遍歷右部分,此時左側的最高高度已確定,rp記錄右側的最高高度
{
if (height[i] > rp) //如果右側有更高的柱子,則提高標尺
rp = height[i];
else
w += rp - height[i];
}
return w;
}
};
方法三:用棧模擬,每個柱子高度若小于棧頂元素則壓入,否則就把棧里所有小于等于當前值的元素全部彈出并計算體積。時間復雜度O(n),空間復雜度O(n)。
class Solution {
public:
int trap(vector<int>& height) {
int n = height.size();
stack<pair<int, int>> s; //記錄下標為 i
的柱子的高度和下標 i
int w = 0;
for (int i = 0; i < n; i ++)
{
int ht = 0; //前一個棧頂的柱高
while(!s.empty())
{
int bar = s.top().first; //棧頂柱高
int pos = s.top().second; //棧頂柱下標
w += ( min(bar, height[i]) - ht ) * (i - pos - 1);
ht = bar;
if (height[i] < bar) //當前柱高小于棧頂元素高度,不需要進棧,上一步已計算其上面能存水體積,繼續處理下一個柱子
break;
else
s.pop(); //否則遍歷處理、彈出所有比當前柱高小的棧中元素
}
s.push(make_pair(height[i], i));
}
return w;
}
};