初级版
给定 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 个单位的雨水(蓝色部分表示雨水)。
示例 2:
输入:height = [4,2,0,3,2,5]
输出:9
刚看到此题,觉得好难啊,但是比较有趣,就尝试着解一下。
从图中可以看出,每个位置的接水量,取决于左右两侧高度的最小值,需要向两侧依次遍历下去,才能确保找到最大的接水量。
那我们可以先正向遍历一遍,找到左侧最大高度,再反向遍历,找到右侧最大高度。然后将两侧高度比较,取小的,再减去当前位置的高度,就是当前单位蓄水量。
/**
* @param {number[]} height
* @return {number}
*/
var trap = function(height) {
let left = [], right = [];
let n = height.length;
left[0] = height[0];
for (let i = 1; i < n; i++) {
left[i] = Math.max(height[i], left[i - 1]);
}
right[n - 1] = height[n - 1];
for (let j = n - 2; j >= 0; j--) {
right[j] = Math.max(height[j], right[j + 1]);
}
let ans = 0;
for (let k = 0; k < n; k++) {
ans += Math.min(left[k], right[k]) - height[k];
}
return ans;
};
时间复杂度:O(n)
空间复杂度:O(n)
方法二:
- 既然左右两侧都需要遍历,那么可以尝试使用双指针。
- 左指针向右遍历,右指针向左遍历。
- 左右指针需要不断更新最大值,然后比较左右指针指向的位置哪个小。
- 如果左侧小,就说明取左侧最大高度与当前高度做差。
- 反之,取右侧最大高度与当前高度做差。
/**
* @param {number[]} height
* @return {number}
*/
var trap = function(height) {
let left = 0, right = height.length - 1;
let leftMax = height[0], rightMax = height[height.length - 1];
let ans = 0;
while (left < right) {
leftMax = Math.max(leftMax, height[left]);
rightMax = Math.max(rightMax, height[right]);
if (height[left] < height[right]) {
ans += leftMax - height[left];
left++;
} else {
ans += rightMax - height[right];
right--;
}
}
return ans;
};
时间复杂度:O(n)
空间复杂度:O(1)
进阶版
给你一个 m x n 的矩阵,其中的值均为非负整数,代表二维高度图每个单元的高度,请计算图中形状最多能接多少体积的雨水。
示例 1:
输入: heightMap = [[1,4,3,1,3,2],[3,2,1,3,2,4],[2,3,3,2,3,1]]
输出: 4
解释: 下雨后,雨水将会被上图蓝色的方块中。总的接雨水量为1+2+1=4。
示例 2:
输入: heightMap = [[3,3,3,3,3],[3,2,2,2,3],[3,2,1,2,3],[3,2,2,2,3],[3,3,3,3,3]]
输出: 10
- 我们假设方块的索引为
(i, j),方块的高度为heightMap[i][j],方块接水后的高度为water[i][j]。 - 则我们知道方块
(i, j)的接水后的高度为:water[i][j] = max(heightMap[i][j], min(water[i-1][j], water[i+1][j], water[i][j-1], water[i][j+1])) - 我们知道方块
(i, j)实际接水的容量计算公式为water[i][j] - heightMap[i][j]。
var trapRainWater = function(heightMap) {
const m = heightMap.length;
const n = heightMap[0].length;
const dirs = [-1, 0, 1, 0, -1];
let maxHeight = 0;
for (let i = 0; i < m; ++i) {
for (let j = 0; j < n; ++j) {
maxHeight = Math.max(maxHeight, heightMap[i][j]);
}
}
const water = new Array(m).fill(0).map(() => new Array(n).fill(0));
for (let i = 0; i < m; ++i) {
for (let j = 0; j < n; ++j){
water[i][j] = maxHeight;
}
}
const qu = [];
for (let i = 0; i < m; ++i) {
for (let j = 0; j < n; ++j) {
if (i == 0 || i == m - 1 || j == 0 || j == n - 1) {
if (water[i][j] > heightMap[i][j]) {
water[i][j] = heightMap[i][j];
qu.push([i, j]);
}
}
}
}
while (qu.length) {
const curr = qu.shift();
const x = curr[0];
const y = curr[1];
for (let i = 0; i < 4; ++i) {
const nx = x + dirs[i], ny = y + dirs[i + 1];
if (nx < 0 || nx >= m || ny < 0 || ny >= n) {
continue;
}
if (water[x][y] < water[nx][ny] && water[nx][ny] > heightMap[nx][ny]) {
water[nx][ny] = Math.max(water[x][y], heightMap[nx][ny]);
qu.push([nx, ny]);
}
}
}
let res = 0;
for (let i = 0; i < m; ++i) {
for (let j = 0; j < n; ++j) {
res += water[i][j] - heightMap[i][j];
}
}
return res;
};
时间复杂度:O((M^2N^2)
空间复杂度:O(MN)