题目

思路
- 方法1:先得到每根柱子左右两边最高的柱子,计算以每根柱子为中心所能盛水量,结果累加
- 方法2:双指针,优化left、right数组,两边向中间遍历,实时维护最高的柱子。每次以最低柱子为目标,计算盛水量,结果累加
代码
/*
方法一:暴力法
思路:
期望知道每个柱子i左右两边的最高的那根柱子
以每根柱子为中心,计算每根柱子可盛水量,即宽 = 1,只需想办法计算高度
一根柱子可盛水量:
左边最高的那根柱子,右边最高的那根柱子,两者取min,就是当前柱子可盛水的高度
可以先用 left[i],right[i] 数组记录下每个柱子i左右边的最高柱子
*/
int trap(vector<int>& a)
{
int n = a.size()
vector<int> left(n)
vector<int> right(n)
//初始化 left、right数组
int Lmax = a[0]
for(int i=1
{
left[i] = Lmax
Lmax = max(Lmax,a[i])
}
int Rmax = a[n-1]
for(int i=n-2
{
right[i] = Rmax
Rmax = max(Rmax,a[i])
}
int ret = 0
for(int i=1
{
int curRet = 1*(min(left[i],right[i])-a[i])
if(curRet > 0) //两边都比当前低,不能盛水
{
ret += curRet
}
}
return ret
}
/*
方法二:双指针
思路:
方法一空间O(n),可以用双指针遍历来优化空间消耗
双指针,是纯遍历的任务
左右两边,用Lmax,Rmax 分别维护从左到右,从右到左的最大值
双指针 遍历的 i,j,就是计算i,j柱子为中心所能盛水量
i,j负责遍历所有位置,每一根柱子都计算其能盛水量,相当于也是以宽度=1的柱子为中心计算盛水量
每次的目的是找 i,j中更低的柱子,以它为中心计算盛水量,盛水量取决于两边最大高度,即 min(Lmax,Rmax)
但,<官方题解>中,a[i] < a[j]时,可以保证 Lmax < Rmax,可以不需要判断 min(Lmax,Rmax),有点难理解,但是举个例子就明白了:
根据下面代码:
若 a[i] < a[j],此时必然 Lmax < Rmax,
因为若 Lmax >= Rmax的话,即a[i]左边还有更高的柱子,
那么这根"很高的柱子"会让右边指针j一直更新: j--,
即,这个"很高的柱子"会一直触发 if(a[j] < a[i]),a[i]就是这根"很高的柱子",而不可能执行到 if(a[i] < a[j])的情况
*/
int trap(vector<int>& a)
{
int n = a.size()
int ret = 0
int Lmax = 0
int Rmax = 0
int i = 0
int j = n-1
while(i<j)
{
Lmax = max(Lmax,a[i])
Rmax = max(Rmax,a[j])
if(a[i] < a[j])
{
// ret += (Lmax-a[i])
ret += (min(Lmax,Rmax)-a[i])
i++
}
else
{
// ret += (Rmax-a[j])
ret += (min(Rmax,Lmax)-a[j])
j--
}
}
return ret
}