LeetCode 42. 接雨水
阿新 • • 發佈:2020-12-24
演算法1
(三次線性掃描)\(O(n)\)
每一列能儲水的量,由該列左邊最高的柱子,和該列右邊最高的柱子決定。計算公式為\(V[i] = min(左邊最高的柱子高度,右邊最高的柱子高度)-height[i]\)
-
先線性掃描一遍,統計出每個柱子左邊最高柱子的高度(這個最高的柱子有可能是自己)
-
再掃描一遍,統計出每個柱子右邊最高柱子的高度
-
最後計算總的結果
時間複雜度
線性掃描三遍,所以是\(O(3n)\),也就是\(O(n)\)
空間複雜度
需要額外使用兩個陣列,\(O(n)\)
C++ 程式碼
class Solution { public: int trap(vector<int>& height) { int n = height.size(); if (!n) return 0; vector<int> left(n), right(n); left[0] = height[0]; for (int i = 1; i < n; i ++) left[i] = max(left[i-1], height[i]); right[n-1] = height[n-1]; for (int i = n-2; i >= 0; i --) right[i] = max(right[i+1], height[i]); int res = 0; for (int i = 0; i < n; i ++) res += min(left[i], right[i]) - height[i]; return res; } };
演算法2
(單調棧)\(O(n)\)
對於每一個柱子,我們將其視為能夠儲水的凹槽的右邊的柱子,去搜索在它左邊能夠構成凹槽的兩個要素:一個比自己矮的柱子\(a\),和一個比\(a\)要高、在\(a\)左邊的的柱子\(b\)。第一個要素我們可以在遍歷的時候設定條件,第二個要素我們發現有這樣的逆序關係:\(height[a] < height[b]\)但是\(a>b\),因此我們可以使用一個嚴格單調遞減的單調棧來儲存這些柱子。設單調棧為\(st\)
- 線性掃描,當要加入的柱子比棧頂元素
st.top()
高,則獲取第一個要素,凹槽的底部,記作low_index
然後出棧。 - 之後,假如棧不空的話,出棧之後的
st
st.top()
就是我們要找的第二個要素,凹槽的左側,記作left_high_index
- 計算當前形成的凹槽容量,
V = (i - left_high_index - 1) * (min(height[left_high_index], height[i]) - height[low_index])
;
時間複雜度
每個元素最多隻會被入棧出棧一次,所以是\(O(n)\)
空間複雜度
額外使用了一個數組來維護單調棧,所以是\(O(n)\)
C++ 程式碼
class Solution { public: int trap(vector<int>& height) { int n = height.size(); if (!n) return 0; vector<int> st(n); int res = 0; for (int i = 0; i < n; i ++) { while(!st.empty() && height[i] >= height[st.back()]) { int low_index = st.back(); st.pop_back(); if (st.empty()) break; int left_high_index = st.back(); res += (i - left_high_index - 1) * (min(height[i], height[left_high_index]) - height[low_index]); } st.push_back(i); } return res; } };