双指针
11.盛水最多的容器
难度:⭐️⭐️
给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
说明:你不能倾斜容器。
示例 1:

输入:[1,8,6,2,5,4,8,3,7]
输出:49
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
示例 2:
输入:height = [1,1]
输出:1
提示:
- n == height.length
- 2 <= n <= 105
- 0 <= height[i] <= 104
解法一 双指针
左右指针初始指向边界,高度较小的指针向中心移动,移动过程中实时计算面积。
时间复杂度:O(n)
空间复杂度:O(1)
双指针
class Solution {
public int maxArea(int[] height) {
int max = 0;
int left = 0;
int right = height.length - 1;
while (left < right) {
if (height[left] < height[right]) {
max = Math.max(max, height[left] * (right - left));
left++;
} else {
max = Math.max(max, height[right] * (right - left));
right--;
}
}
return max;
}
}
42.接雨水
难度:⭐️⭐️⭐️
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
解法一 双指针
从两端向中间移动,维护左右两边的最大高度,雨水量取决于两边较小值。
双指针
public int trap(int[] height) {
if (height == null || height.length == 0) {
return 0;
}
int left = 0;
int right = height.length - 1;
int leftMax = 0;
int rightMax = 0;
int water = 0;
while (left < right) {
if (height[left] < height[right]) {
if (height[left] >= leftMax) {
leftMax = height[left];
} else {
water += leftMax - height[left];
}
left++;
} else {
if (height[right] >= rightMax) {
rightMax = height[right];
} else {
water += rightMax - height[right];
}
right--;
}
}
return water;
}
解法二 动态规划
先预处理出每个位置左边最大值和右边最大值,然后遍历计算每个位置能接的雨水。
动态规划
public int trap(int[] height) {
int n = height.length;
if (n == 0) return 0;
// 左边最大值数组
int[] leftMax = new int[n];
leftMax[0] = height[0];
for (int i = 1; i < n; i++) {
leftMax[i] = Math.max(leftMax[i - 1], height[i]);
}
// 右边最大值数组
int[] rightMax = new int[n];
rightMax[n - 1] = height[n - 1];
for (int i = n - 2; i >= 0; i--) {
rightMax[i] = Math.max(rightMax[i + 1], height[i]);
}
// 计算每个位置能接的雨水
int water = 0;
for (int i = 0; i < n; i++) {
water += Math.min(leftMax[i], rightMax[i]) - height[i];
}
return water;
}
解法三 单调栈
使用栈保存下标,遇到比栈顶低的柱子就计算积水,利用单调栈的性质减少计算量。
单调栈
public int trap(int[] height) {
int n = height.length;
Deque<Integer> stack = new ArrayDeque<>();
int water = 0;
for (int i = 0; i < n; i++) {
while (!stack.isEmpty() && height[i] > height[stack.peek()]) {
int top = stack.pop();
if (stack.isEmpty()) break;
int left = stack.peek();
int right = i;
int width = right - left - 1;
int heightDiff = Math.min(height[left], height[right]) - height[top];
water += width * heightDiff;
}
stack.push(i);
}
return water;
}