package stack; import java.util.Deque; import java.util.LinkedList; /** * 题目: 42. 接雨水 (trap) * 描述:给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 * 示例 1: * 输入:height = [0,1,0,2,1,0,1,3,2,1,2,1] * 输出:6 * 解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 * * 链接:https://leetcode.cn/problems/trapping-rain-water/ */ //困难题 不会 public class Trap { //暴力解法 public int trap1(int[] height) { int sum = 0; for (int i = 0; i < height.length; i++) { // 第一个柱子和最后一个柱子不接雨水 if (i == 0 || i == height.length - 1) { continue; } int rHeight = height[i]; // 记录右边柱子的最高高度 int lHeight = height[i]; // 记录左边柱子的最高高度 for (int r = i + 1; r < height.length; r++) { if (height[r] > rHeight) { rHeight = height[r]; } } for (int l = i - 1; l >= 0; l--) { if (height[l] > lHeight) { lHeight = height[l]; } } int h = Math.min(lHeight, rHeight) - height[i]; if (h > 0) { sum += h; } } return sum; } //动态规划 public int trap2(int[] height) { if (height.length <= 2) return 0; int n = height.length; int[] maxLeft = new int[n]; int[] maxRight = new int[n]; // 记录每个柱子左边柱子最大高度 maxLeft[0] = height[0]; for (int i = 1; i < n; i++) { maxLeft[i] = Math.max(height[i], maxLeft[i - 1]); } // 记录每个柱子右边柱子最大高度 maxRight[n - 1] = height[n - 1]; for (int i = n - 2; i >= 0; i--) { maxRight[i] = Math.max(height[i], maxRight[i + 1]); } // 求和 int sum = 0; for (int i = 1; i < n-1; i++) { int count = Math.min(maxLeft[i-1], maxRight[i+1]) - height[i]; if (count > 0) { sum += count; } } return sum; } //单调栈 public int trap(int[] height) { int sum = 0; Deque stack = new LinkedList<>(); for (int i = 0; i < height.length; i++) { // 当栈不为空且当前柱子的高度大于栈顶柱子的高度时 while (!stack.isEmpty() && height[i] > height[stack.peek()]) { int top = stack.pop(); // 如果栈为空,则没有左边的柱子来接雨水 if (stack.isEmpty()) break; // 计算当前柱子与栈顶柱子之间的距离 int distance = i - stack.peek() - 1; // 计算可以接的雨水高度:两边较低的高度减去中间柱子的高度 int boundedHeight = Math.min(height[i], height[stack.peek()]) - height[top]; sum += distance * boundedHeight; } // 将当前索引入栈 stack.push(i); } return sum; } }