解法一:暴力无脑解题法(超时)
对每一个格子进行推算,根据左右最高的格子数来计算能接水的单位数,最后逐一相加
class Solution:
def trap(self, height: List[int]) -> int:
ans = 0
for i in range(len(height)):
max_left, max_right = 0,0
# 寻找 max_left
for j in range(0,i):
max_left = max(max_left,height[j])
# 寻找 max_right
for j in range(i,len(height)):
max_right = max(max_right,height[j])
if min(max_left,max_right) > height[i]:
ans += min(max_left,max_right) - height[i]
return ans
解法二:动态规划
在暴力解题的基础上,使用数组来放置maxleft和maxright,降低时间复杂度,遍历次数大大减少
class Solution:
def trap(self, height: List[int]) -> int:
# 边界条件
if not height: return 0
n = len(height)
maxleft = [0] * n
maxright = [0] * n
ans = 0
# 初始化
maxleft[0] = height[0]
maxright[n-1] = height[n-1]
# 设置备忘录,分别存储左边和右边最高的柱子高度
for i in range(1,n):
maxleft[i] = max(height[i],maxleft[i-1])
for j in range(n-2,-1,-1):
maxright[j] = max(height[j],maxright[j+1])
# 一趟遍历,比较每个位置可以存储多少水
for i in range(n):
if min(maxleft[i],maxright[i]) > height[i]:
ans += min(maxleft[i],maxright[i]) - height[i]
return ans
解法三:分层+双指针
接完雨水后的图形,看起来会有很明显的特点,从前后分别往中间靠,一定是递增的,一直到最高点
所以分设两个指针left,right,从前后分别向中间移动,在遇到较之前大的数字后停下,两个指针进行计算right-left+1得出这一层的单元块有多少个,然后将每一层的块数加起来,就是接水后的块数,再减去输入的块数,就是雨水的单位数,图解如下
class Solution:
def trap(self, height: List[int]) -> int:
n=len(height)
left,right=0,n-1
SUM,tmp,high=0,0,1
while(left<=right):
while(left<=right and height[left]<high):
SUM+=height[left]
left+=1
while(right>=left and height[right]<high):
SUM+=height[right]
right-=1
high+=1
tmp+=right-left+1
return tmp-SUM
解法四:双指针+几何法
另外解法三也可以改进一下,因为你会发现,如果两个指针相对移动的同时,分别记录遇到的最大值,然后每一轮都将他们的值相加,最后的结果会是以max(list)和len(list)为边长的矩形格子数加上接雨水后的图形,看下图
红线和黄线分别是left和right指针移动路线的值
class Solution:
def trap(self, height: List[int]) -> int:
lmax, rmax, res = 0, 0, 0
for i in range(len(height)):
lmax = max(lmax, height[i])
rmax = max(rmax, height[-1-i])
res += lmax + rmax - height[i]
return res - lmax * len(height)
解法五:几何法
如图分成四个块,要求的是灰色部分的单位块数,由大矩形块数减去黑色部分也就是输入的列表的求和,再减去红色和淡蓝色的部分,这两部分分别是从前和后向中间遍历到最高点,记录最大值与最高点的差值
class Solution:
def trap(self, height: List[int]) -> int:
if not height: return 0
max_h = max(height)
rain = max_h * len(height) - sum(height)
m_h = 0
for h in height:
if h >= max_h: break
if h > m_h: m_h = h
rain -= max_h - m_h
m_h = 0
for h in reversed(height):
if h >= max_h: break
if h > m_h: m_h = h
rain -= max_h - m_h
return rain
!!!本文参考了力扣大神的解法,特此说明!!!