跳转至

42.接雨水 (Hard)*

题目描述*

标签*

栈;数组;双指针

思路 & 代码*

看到题目有一点思路,可以一行一行求,不过感觉这样会很慢,事实确实是超时了。。。因为这种方法遍历了那么多次而每次只算一层的。时间复杂度 O(\max \cdot n)

按行求不行,可以试一下按列求。感觉要麻烦一些,求当前列最后能有多少水,就是确定左右两边最高的柱子高度,只有在当前高度小于左右最高柱子的较小者时才能接到水。时间复杂度 O(n^2)。然而又超时了。。。

按列求的方法最耗时的应该就是找左右的最高柱子,可以优化一下。一次性先求出来就行了。时间复杂度降为 O(n)

先求出所有位置对应的左右最高柱子确实快了很多,但是增加了两个额外的数组,可以把更新 maxl 和 maxr 的操作都放到一起,因为一次只用一对值。不过有一个问题就是 maxl 的更新是从左到右,而 maxr 的更新是从右到左,可以使用双指针优化。时间复杂度 O(n),空间复杂度 O(1)

还可以用栈记录柱子高度,当当前高度小于栈顶高度时,入栈,大于时出栈,并将计算这段的水量。时间复杂度 O(n)

class Solution {
public:
    int trap(vector<int>& height) {
        int n = height.size();
        if(n == 0) {
            return 0;
        }
        int m = *max_element(height.begin(), height.end());
        int res = 0;
        for(int i = 1; i <= m; i++) {
            int tmp = 0;
            bool flag = false;
            for(int j = 0; j < n; j++) {
                if(height[j] < i && flag) {
                    tmp++;
                }else if(height[j] >= i) {
                    res += tmp;
                    tmp = 0;
                    flag = true;
                }
            }
        }
        return res;
    }
};
class Solution {
public:
    int trap(vector<int>& height) {
        int n = height.size();
        if(n == 0) {
            return 0;
        }
        int res = 0;
        for(int i = 1; i < n - 1; i++) {
            int l = *max_element(height.begin(), height.begin() + i);
            int r = *max_element(height.begin() + i + 1, height.end());
            if(height[i] < l && height[i] < r) {
                res += min(l, r) - height[i];
            }
        }
        return res;
    }
};
class Solution {
public:
    int trap(vector<int>& height) {
        int n = height.size();
        if(n == 0) {
            return 0;
        }
        vector<int> maxl(n, 0);
        maxl[0] = height[0];
        for(int i = 1; i < n; i++) {
            maxl[i] = max(maxl[i - 1], height[i - 1]);
        }
        vector<int> maxr(n, 0);
        maxr[n - 1] = height[n - 1];
        for(int i = n - 2; i >= 0; i--) {
            maxr[i] = max(maxr[i + 1], height[i + 1]);
        }
        int res = 0;
        for(int i = 1; i < n - 1; i++) {
            int l = maxl[i];
            int r = maxr[i];
            if(height[i] < l && height[i] < r) {
                res += min(l, r) - height[i];
            }
        }
        return res;
    }
};
class Solution {
public:
    int trap(vector<int>& height) {
        int n = height.size();
        if(n == 0) {
            return 0;
        }
        int l = 1;
        int r = n - 2;
        int maxl = height[0];
        int maxr = height[n - 1];
        int res = 0;
        while(l <= r) {
            if(height[l - 1] < height[r + 1]) {
                maxl = max(maxl, height[l - 1]);
                if(maxl > height[l]) {
                    res += maxl - height[l];
                }
                l++;
            }else {
                maxr = max(maxr, height[r + 1]);
                if(maxr > height[r]) {
                    res += maxr - height[r];
                }
                r--;
            }
        }
        return res;
    }
};
class Solution {
public:
    int trap(vector<int>& height) {
        int n = height.size();
        if(n == 0) {
            return 0;
        }
        stack<int> st;
        int cur = 0;
        int res = 0;
        while(cur < n) {
            while(!st.empty() && height[st.top()] < height[cur]) {
                int h = height[st.top()];
                st.pop();
                // 栈中只有一个元素,也就是相邻的两个柱子
                if(st.empty()) {
                    break;
                }
                int d = cur - st.top() - 1;
                res += d * (min(height[st.top()], height[cur]) - h);
            }
            st.push(cur);
            cur++;
        }
        return res;
    }
};

最后更新: July 23, 2022