1. 程式人生 > 實用技巧 >LeetCode 42. 接雨水

LeetCode 42. 接雨水

題目,leetcodeacwing

看這篇題解

演算法1

(三次線性掃描)\(O(n)\)

每一列能儲水的量,由該列左邊最高的柱子,和該列右邊最高的柱子決定。計算公式為\(V[i] = min(左邊最高的柱子高度,右邊最高的柱子高度)-height[i]\)

  1. 先線性掃描一遍,統計出每個柱子左邊最高柱子的高度(這個最高的柱子有可能是自己)

  2. 再掃描一遍,統計出每個柱子右邊最高柱子的高度

  3. 最後計算總的結果

時間複雜度

線性掃描三遍,所以是\(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\)

  1. 線性掃描,當要加入的柱子比棧頂元素st.top()高,則獲取第一個要素,凹槽的底部,記作low_index然後出棧。
  2. 之後,假如棧不空的話,出棧之後的st​
    的棧頂元素st.top()​就是我們要找的第二個要素,凹槽的左側,記作left_high_index
  3. 計算當前形成的凹槽容量,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;
    }
};