您好,登錄后才能下訂單哦!
這篇“C++收集雨水問題怎么解決”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“C++收集雨水問題怎么解決”文章吧。
Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.
The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped. Thanks Marcos for contributing this image!
Example:
Input: [0,1,0,2,1,0,1,3,2,1,2,1]
Output: 6
這道收集雨水的題跟之前的那道 Largest Rectangle in Histogram 有些類似,但是又不太一樣,先來看一種方法,這種方法是基于動態規劃 Dynamic Programming 的,維護一個一維的 dp 數組,這個 DP 算法需要遍歷兩遍數組,第一遍在 dp[i] 中存入i位置左邊的最大值,然后開始第二遍遍歷數組,第二次遍歷時找右邊最大值,然后和左邊最大值比較取其中的較小值,然后跟當前值 A[i] 相比,如果大于當前值,則將差值存入結果,參見代碼如下:
C++ 解法一:
class Solution { public: int trap(vector<int>& height) { int res = 0, mx = 0, n = height.size(); vector<int> dp(n, 0); for (int i = 0; i < n; ++i) { dp[i] = mx; mx = max(mx, height[i]); } mx = 0; for (int i = n - 1; i >= 0; --i) { dp[i] = min(dp[i], mx); mx = max(mx, height[i]); if (dp[i] > height[i]) res += dp[i] - height[i]; } return res; } };
Java 解法一:
public class Solution { public int trap(int[] height) { int res = 0, mx = 0, n = height.length; int[] dp = new int[n]; for (int i = 0; i < n; ++i) { dp[i] = mx; mx = Math.max(mx, height[i]); } mx = 0; for (int i = n - 1; i >= 0; --i) { dp[i] = Math.min(dp[i], mx); mx = Math.max(mx, height[i]); if (dp[i] - height[i] > 0) res += dp[i] - height[i]; } return res; } }
再看一種只需要遍歷一次即可的解法,這個算法需要 left 和 right 兩個指針分別指向數組的首尾位置,從兩邊向中間掃描,在當前兩指針確定的范圍內,先比較兩頭找出較小值,如果較小值是 left 指向的值,則從左向右掃描,如果較小值是 right 指向的值,則從右向左掃描,若遇到的值比當較小值小,則將差值存入結果,如遇到的值大,則重新確定新的窗口范圍,以此類推直至 left 和 right 指針重合,參見代碼如下:
C++ 解法二:
class Solution { public: int trap(vector<int>& height) { int res = 0, l = 0, r = height.size() - 1; while (l < r) { int mn = min(height[l], height[r]); if (mn == height[l]) { ++l; while (l < r && height[l] < mn) { res += mn - height[l++]; } } else { --r; while (l < r && height[r] < mn) { res += mn - height[r--]; } } } return res; } };
Java 解法二:
public class Solution { public int trap(int[] height) { int res = 0, l = 0, r = height.length - 1; while (l < r) { int mn = Math.min(height[l], height[r]); if (height[l] == mn) { ++l; while (l < r && height[l] < mn) { res += mn - height[l++]; } } else { --r; while (l < r && height[r] < mn) { res += mn - height[r--]; } } } return res; } }
我們可以對上面的解法進行進一步優化,使其更加簡潔:
C++ 解法三:
class Solution { public: int trap(vector<int>& height) { int l = 0, r = height.size() - 1, level = 0, res = 0; while (l < r) { int lower = height[(height[l] < height[r]) ? l++ : r--]; level = max(level, lower); res += level - lower; } return res; } };
Java 解法三:
public class Solution { public int trap(int[] height) { int l = 0, r = height.length - 1, level = 0, res = 0; while (l < r) { int lower = height[(height[l] < height[r]) ? l++ : r--]; level = Math.max(level, lower); res += level - lower; } return res; } }
其實用 stack 的方法博主感覺更容易理解,思路是,遍歷高度,如果此時棧為空,或者當前高度小于等于棧頂高度,則把當前高度的坐標壓入棧,注意這里不直接把高度壓入棧,而是把坐標壓入棧,這樣方便在后來算水平距離。當遇到比棧頂高度大的時候,就說明有可能會有坑存在,可以裝雨水。此時棧里至少有一個高度,如果只有一個的話,那么不能形成坑,直接跳過,如果多余一個的話,那么此時把棧頂元素取出來當作坑,新的棧頂元素就是左邊界,當前高度是右邊界,只要取二者較小的,減去坑的高度,長度就是右邊界坐標減去左邊界坐標再減1,二者相乘就是盛水量啦,參見代碼如下:
C++ 解法四:
class Solution { public: int trap(vector<int>& height) { stack<int> st; int i = 0, res = 0, n = height.size(); while (i < n) { if (st.empty() || height[i] <= height[st.top()]) { st.push(i++); } else { int t = st.top(); st.pop(); if (st.empty()) continue; res += (min(height[i], height[st.top()]) - height[t]) * (i - st.top() - 1); } } return res; } };
Java 解法四:
class Solution { public int trap(int[] height) { Stack<Integer> s = new Stack<Integer>(); int i = 0, n = height.length, res = 0; while (i < n) { if (s.isEmpty() || height[i] <= height[s.peek()]) { s.push(i++); } else { int t = s.pop(); if (s.isEmpty()) continue; res += (Math.min(height[i], height[s.peek()]) - height[t]) * (i - s.peek() - 1); } } return res; } }
以上就是關于“C++收集雨水問題怎么解決”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。