(关注数据结构和算法,了解更多新知识)
最近一网友问到:字节的是不是都会接雨水,这里说的接雨水实际上是LeetCode上的一道算法题,因为这题在LeetCode上的难度为困难,并且又是字节常考的一道题,所以该网友才会这样问。
我们来看下其他网友的回复,甚至有的网友调侃连保洁阿姨都会,从大家的评论中我们可以看到,实际上这题不算太难。
问题描述
来源:LeetCode第42题
难度:困难
给定 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
n == height.length
1 <= n <= 2 * 10^4
0 <= height[i] <= 10^5
问题分析
这题解法比较多,可以使用双指针,单调栈以及动态规划来解决。我们这里只介绍其中的一种,看一下动态规划的解决方式。
首先从左往右遍历数组,记录每一个位置左边(包含自己)的最大值,然后再从右往左遍历数组,记录每一个位置右边(包含自己)的最大值。
两次遍历完之后我们就知道每一个位置左边和右边的最大值了,左右两边的最大值围成的区域可以看作是一个桶,桶的高度取决于这两个值的最小值,知道桶的高度就可以计算当前位置所能容纳的水了,最后只需要计算所有位置容纳的水量即可。
JAVA:
public int trap(int[] height) {
int length = height.length;
int[] leftMax = new int[length];
leftMax[0] = height[0];
for (int i = 1; i < length; ++i)// 计算左边的最大值
leftMax[i] = Math.max(leftMax[i - 1], height[i]);
int[] rightMax = new int[length];
rightMax[length - 1] = height[length - 1];
for (int i = length - 2; i >= 0; --i)// 计算右边的最大值
rightMax[i] = Math.max(rightMax[i + 1], height[i]);
// 根据左右两边的最大值来确定当前柱子所能容纳的水量。
int water = 0;
for (int i = 0; i < length; ++i)
water += Math.min(leftMax[i], rightMax[i]) - height[i];
return water;
}
C++:
public:
int trap(vector<int> &height) {
int length = height.size();
int leftMax[length];
leftMax[0] = height[0];
for (int i = 1; i < length; ++i)// 计算左边的最大值
leftMax[i] = max(leftMax[i - 1], height[i]);
int rightMax[length];
rightMax[length - 1] = height[length - 1];
for (int i = length - 2; i >= 0; --i)// 计算右边的最大值
rightMax[i] = max(rightMax[i + 1], height[i]);
// 根据左右两边的最大值来确定当前柱子所能容纳的水量。
int water = 0;
for (int i = 0; i < length; ++i)
water += min(leftMax[i], rightMax[i]) - height[i];
return water;
}
C:
int trap(int *height, int heightSize) {
int leftMax[heightSize];
leftMax[0] = height[0];
for (int i = 1; i < heightSize; ++i)// 计算左边的最大值
leftMax[i] = fmax(leftMax[i - 1], height[i]);
int rightMax[heightSize];
rightMax[heightSize - 1] = height[heightSize - 1];
for (int i = heightSize - 2; i >= 0; --i)// 计算右边的最大值
rightMax[i] = fmax(rightMax[i + 1], height[i]);
// 根据左右两边的最大值来确定当前柱子所能容纳的水量。
int water = 0;
for (int i = 0; i < heightSize; ++i)
water += fmin(leftMax[i], rightMax[i]) - height[i];
return water;
}
Python:
def trap(self, height: List[int]) -> int:
length = len(height)
leftMax = [0] * length
leftMax[0] = height[0]
for i in range(1, length): # 计算左边的最大值
leftMax[i] = max(leftMax[i - 1], height[i])
rightMax = [0] * length
rightMax[length - 1] = height[length - 1]
for i in range(length - 2, -1, -1): # 计算右边的最大值
rightMax[i] = max(rightMax[i + 1], height[i])
# 根据左右两边的最大值来确定当前柱子所能容纳的水量。
water = 0
for i in range(0, length):
water += min(leftMax[i], rightMax[i]) - height[i]
return water
笔者简介
博哥,真名:王一博,毕业十多年,《算法秘籍》作者,专注于数据结构和算法的讲解,在全球30多个算法网站中累计做题2000多道,在公众号中写算法题解800多题,对算法题有自己独特的解题思路和解题技巧,喜欢的可以给个关注,也可以下载我整理的1000多页的PDF算法文档。