【科学刷题】接雨水:从1维到2维

1 【1维】接雨水

42. 接雨水

1.1 DP 解法

时间复杂度: O ( N ) O(N) O(N)

  • Python
class Solution:
    def trap(self, height: List[int]) -> int:
        sum = 0
        n = len(height)
        max_left = [0] * n
        max_right = [0] * n
        for i in range(1, n - 1):
            max_left[i] = max(max_left[i - 1], height[i - 1])
        for i in reversed(range(1, n - 1)):  # range(n - 2, 0, -1):
            max_right[i] = max(max_right[i + 1], height[i + 1])
        for i in range(1, n - 1):
            min_height = min(max_left[i], max_right[i])
            sum += max(0, min_height - height[i])
        return sum
  • CPP
class Solution {
public:
    int trap(vector<int>& height) {
        int n=height.size();
        vector<int> left(n,0);
        vector<int> right(n,0);
        int ans=0;
        for(int i=1;i<n;++i){
            left[i]=max(left[i-1],height[i-1]);
        }
        for(int i=n-2;i>=0;--i){
            right[i]=max(right[i+1],height[i+1]);
        }
        for(int i=1;i<n-1;++i){
            ans+=max(0,
               min(left[i],right[i])-height[i]
            );
        }
        return ans;
    }
};

1.2 单调栈 解法

时间复杂度: O ( N ) O(N) O(N)

class Solution:
    def trap(self, height: List[int]) -> int:
        n = len(height)
        stack = []
        ans = 0
        #         □
        # □       □
        # □ □   □ □
        # 2 1 0 1 3
        #       ↑ ↑ 触发出栈情况
        # h:    1 1
        # l:    1 3
        # 出站后的pre变量代表了前一个高度
        for i in range(n):
            while stack and height[stack[-1]] < height[i]:
                pre = stack.pop()
                # 如果stack为空,表示 [2, 3, 4] 这种情况,围不起来
                if not stack:
                    break
                t = stack[-1]
                h = min(height[t], height[i]) - height[pre]  # 当前高度 - 上一个高度
                l = i - t - 1
                ans += h * l
            stack.append(i)
        return ans

1.3 堆 解法

时间复杂度: O ( N log ⁡ N ) O(N\log N) O(NlogN)

class Solution:
    def trap(self, height: List[int]) -> int:
        if not height:
            return 0
        n = len(height)
        vis = [0] * n
        pq = []
        for i in (0, n - 1):
            vis[i] = True
            heapq.heappush(pq, (height[i], i))
        ans = 0
        while pq:
            wh, x = heapq.heappop(pq)
            for dx in [-1, 1]:
                cx = x + dx
                if not (0 <= cx < n):
                    continue
                if vis[cx]:
                    continue
                ch = height[cx]
                ans += max(0, wh - ch)
                vis[cx] = True
                heapq.heappush(pq, (max(ch, wh), cx))
        return ans

2【1维】 盛最多水的容器

11. 盛最多水的容器

双指针:

class Solution:
    def maxArea(self, height: List[int]) -> int:
        l = 0
        n = len(height)
        r = n - 1
        ans = 0
        while l < r:
            ans = max((r - l) * min(height[l], height[r]), ans)
            if height[l] < height[r]:
                l += 1
            else:
                r -= 1
        return ans

3【2维】接雨水

407. 接雨水 II

时间复杂度: O ( N M log ⁡ ( N + M ) ) O(NM\log (N+M)) O(NMlog(N+M))

class Solution:
    def trapRainWater(self, heightMap: List[List[int]]) -> int:
        m, n = len(heightMap), len(heightMap[0])
        pq = []
        vis = [[0] * n for _ in range(m)]
        for i in range(m):
            for j in range(n):
                if i in (0, m - 1) or j in (0, n - 1):
                    heapq.heappush(pq, (heightMap[i][j], i, j))
                    vis[i][j] = 1
        dirs = [-1, 0, 1, 0, -1]
        ans = 0
        while pq:
            wh, x, y = heapq.heappop(pq)
            for k in range(4):
                nx, ny = x + dirs[k], y + dirs[k + 1]
                if 0 <= nx < m and 0 <= ny < n and vis[nx][ny] == 0:
                    ch = heightMap[nx][ny]
                    ans += max(0, wh - ch)
                    vis[nx][ny] = 1
                    heapq.heappush(pq, (max(wh, ch), nx, ny))
        return ans
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值