各位题友大家好! 今天是 @负雪明烛 坚持日更的第 68 天。今天力扣上的每日一题是「面试题 17.21. 直方图的水量」。
解题思路
我使用的是 面向列的计算
面向列的计算比面向行的计算更容易,我们只用考虑当前的位置的左右最高木板的高度。
1. 暴力解法
每个位置能接多少雨水,很容易想到「木桶效应」,即是由两边最短的木板限制的。那么直观思路就是,对于每个位置,向左右找最高的木板;当前位置能放的水量是:左右两边最高木板的最低高度 - 当前高度。
这个做法应该是本题的最简单的做法。
下图的红色柱子表示当前要求的位置,两个黄色柱子分别表示左右最高的柱子。
代码也非常简单:
class Solution(object):
def trap(self, height):
res = 0
# 第 0 个位置和 最后一个位置不能蓄水,所以不用计算
for i in range(1, len(height) - 1):
# 求右边的最高柱子
rHeight = max(height[i + 1:])
# 求左边的最高柱子
lHeight = max(height[:i])
# 左右两边最高柱子的最小值 - 当前柱子的高度
h = min(rHeight, lHeight) - height[i]
# 如果能蓄水
if h > 0:
res += h
return res
- 时间复杂度:$O(N^2)$
- 空间复杂度:$O(1)$
2. 动态规划
从上面的代码思路中我们看到,对于每个位置,我们都暴力向两边求最高木板,这里其实是有重复计算的。比较直观的优化思路是:先提前遍历一次,求出每个位置左右最高的模板,把结果保存到数组里。就可以避免在求解接雨水的 for
循环中计算高度了。
class Solution(object):
def trap(self, height):
N = len(height)
# 如果小于等于两个柱子,是无法蓄水的
if N <= 2: return 0
# 求每个位置左边的最高柱子
lHeight = [0] * N
# lHeight 第 0 个位置初始化为 height[0]
lHeight[0] = height[0]
# 求每个位置右边的最高柱子
rHeight = [0] * N
# rHeight 最后一个位置初始化为 height[N - 1]
rHeight[N - 1] = height[N - 1]
# 求每个位置左边最高柱子高度
for i in range(1, N):
lHeight[i] = max(lHeight[i - 1], height[i])
# 求每个位置右边最高柱子高度
for i in range(N - 2, -1, -1):
rHeight[i] = max(rHeight[i + 1], height[i])
res = 0
# 这个思路和上面的暴力解法一样的
for i in range(1, len(height) - 1):
h = min(rHeight[i], lHeight[i]) - height[i]
if h > 0:
res += h
return res
- 时间复杂度:$O(N)$
- 空间复杂度:$O(N)$
3. 双指针
双指针解法是上面的解法的进一步优化,主要作用是为了降低空间复杂度。
使用了两个指针 left
和 right
分别指向左右两个端点的柱子。
另外用 lHeight
和 rHeight
分别表示左右两个指针遇到过的最高的柱子,注意上面的动态规划做法是提前算出来每个位置左右的最高柱子,而双指针解法是在遍历的过程中统计遇到过的最高柱子。
双指针移动的思想是看哪 left 和 right 两个柱子哪个更矮,因为蓄水时的瓶颈是更矮的柱子,而更高的柱子其实是不用考虑的。所以每次把更矮的那个柱子向中间移动。
详细解释可以看 力扣加加 。
class Solution(object):
def trap(self, height):
N = len(height)
if N < 2: return 0
left, right = 0, N - 1
lHeight = rHeight = 0
res = 0
while left < right:
if height[left] < height[right]:
if height[left] < lHeight:
res += lHeight - height[left]
else:
lHeight = height[left]
left += 1
else:
if height[right] < rHeight:
res += rHeight - height[right]
else:
rHeight = height[right]
right -= 1
return res
最近工作非常忙,题解质量降低了,很抱歉。
参考资料:
OK,以上就是 @负雪明烛 写的今天题解的全部内容了,如果你觉得有帮助的话,求赞、求关注、求收藏。如果有疑问的话,请在下面评论,我会及时解答。
关注我,你将不会错过我的精彩动画题解、面试题分享、组队刷题活动,进入主页 @负雪明烛 右侧有刷题组织,从此刷题不再孤单。
祝大家牛年大吉!AC 多多,Offer 多多!我们明天再见!