題面:
思路:
能接雨水的點,必然是比兩邊都低(小)的點。有兩種思路,一種是直接計算每個點的最大貢獻(也就是每個點在縱向上最多能接多少水),另一種就是計算每個點在橫向上有沒有貢獻。
第一種思路,就需要我們能拿到每個點左右兩邊最高的高度,這樣就能計算每個點在縱向上能接多少水,相當于木桶效應。
第二種思路,對于每個點,則需要判斷它左右兩邊是不是都有比它高的點,每次計算橫向上局部能接到水的區域。
官方題解挺好的,具體不再贅述
1. 單調棧
就是第二種思路,每次更新橫向上能接到的水。
int trap(vector<int>& height) {int ans = 0, n = (int)height.size();stack<int> stk;for(int i = 0; i < n; ++ i) {while(!stk.empty() && height[i] > height[stk.top()]) {// 得到當前低點int buttom = stk.top(); stk.pop();if(!stk.empty()) {int j = stk.top();// 如果 height[j] == height[bottom]// 就說明 bottom 的左邊還沒有出現凸出來讓bottom能接到水的邊邊ans += (i - j - 1) * (min(height[i], height[j]) - height[buttom]);}}stk.push(i);}return ans;
}
2. 動態規劃
第一種思路,要拿到每個點左右兩邊的最大高度,就可以考慮線性DP的思想去記錄當前點左右兩邊的最大高度。
l e f t M a x [ i ] = m a x ( l e f t M a x [ i ? 1 ] , h e i g h t [ i ] ) r i g h t M a x [ i ] = m a x ( r i g h t M a x [ i + 1 ] , h e i g h t [ i ] ) g o t W a t e r [ i ] = m i n ( l e f t M a x [ i ] , r i g h t M a x [ i ] ) ? h e i g h t [ i ] leftMax[i]=max(leftMax[i-1],height[i])\\ rightMax[i]=max(rightMax[i+1],height[i])\\ gotWater[i] = min(leftMax[i],\ rightMax[i])-height[i] leftMax[i]=max(leftMax[i?1],height[i])rightMax[i]=max(rightMax[i+1],height[i])gotWater[i]=min(leftMax[i],?rightMax[i])?height[i]
int trap(vector<int>& height) {int ans = 0, n = (int)height.size();vector<int> leftMax(n), rightMax(n);leftMax[0] = height[0]; rightMax[n - 1] = height[n - 1];for(int i = 1; i < n; ++ i) leftMax[i] = max(leftMax[i - 1], height[i]);for(int i = n - 2; i >= 0; -- i) rightMax[i] = max(rightMax[i + 1], height[i]);for(int i = 1; i < n - 1; ++ i)ans += min(leftMax[i], rightMax[i]) - height[i];return ans;
}
雙指針
使用雙指針和臨時變量優化掉 l e f t M a x leftMax leftMax 和 r i g h t M a x rightMax rightMax 兩個數組。
官方題解說:如果 h e i g h t [ l e f t ] < h e i g h t [ r i g h t ] height[left]<height[right] height[left]<height[right],則必有 l e f t M a x < r i g h t M a x leftMax<rightMax leftMax<rightMax。
這主要是因為,我們每次移動的都是 h e i g h t height height 較小的指針,因此如果 l e f t M a x leftMax leftMax 或 r i g h t M a x rightMax rightMax 有更新,則更新了的點 l e f t left left 或 r i g h t right right 在 l e f t M a x leftMax leftMax 或 r i g h t M a x rightMax rightMax 得到新的更新之前會停留一陣子。因此如果 h e i g h t [ l e f t ] < h e i g h t [ r i g h t ] height[left]<height[right] height[left]<height[right],則必有 l e f t M a x < r i g h t M a x leftMax<rightMax leftMax<rightMax。
int trap(vector<int>& height) {int ans = 0, n = (int)height.size();int left = 0, right = n - 1;int leftMax = height[0], rightMax = height[n - 1];while(left < right) {leftMax = max(leftMax, height[left]);rightMax = max(rightMax, height[right]);if(height[left] < height[right])ans += min(leftMax, rightMax) - height[left ++];elseans += min(leftMax, rightMax) - height[right --];}return ans;
}