一、前言
这应该是最近的最后一道动态规划题了,所以我也特地挑了一道很有意思很烧脑的一道题。代码实现非常简单,看懂之后我相信会对大家有所帮助。
二、题目描述
三、题目分析
这个题目乍一看真的很吓人,因为是动态规划,起初你一定会想到状态转移方程,但是突然发现无从下手,这正是这题有意思的地方。我们知道,如果有个区域可以储存水,那水的高度肯定跟左右两边最高的那个边框有关,并且水的高度是边框中小的那个,就如上图那个T型一般。
那我们好像应该通过某种方式获取每一列的左边和右边最高的那个柱子,但是我们又发现,上面装水的区域形状大小都不相同,我们怎么统一呢?很简单,我们只要一列一列算就行了。比如上面那个T型水域,可以拆分成三部分计算。获取第五列右边最高的高度是3,左边最高的高度是2,取min为其中小的那个2,那么第五列水的高度就应该是2减去它本身的高度,如果是正数,说明确实储存了水,如果是负数,则抛弃不谈。因为就像第八列,它的左右两边最大高度都是2,但是2-3=-1,明显不可以储存水,所以不考虑其中。
那么获取左右两边的最大高度怎么算呢?很简单,递归就行
for(int i=1;i<length;i++)
{
max_left[i]=Math.max(max_left[i-1],height[i-1]);
}
for(int i=length-2;i>=0;i--)
{
max_right[i]=Math.max(max_right[i+1],height[i+1]);
}
四、完整代码
public int trap(int[] height) {
int length=height.length;
int []max_left=new int [length];
int []max_right=new int [length];
for(int i=1;i<length;i++)
{
max_left[i]=Math.max(max_left[i-1],height[i-1]);
}
for(int i=length-2;i>=0;i--)
{
max_right[i]=Math.max(max_right[i+1],height[i+1]);
}
int sum=0;
for(int i=1;i<length;i++)
{
int min=Math.min(max_left[i],max_right[i]);
if(min>height[i])
sum+=min-height[i];
}
return sum;
}
五、优化和感言
可以发现上面虽然花大量时间和空间定义了max_left和max_right两个数组,但其实都只用了一次,所以我们可以使用两个变量来代替它,让它随着循环而更新,这样可提高效率。
总的来说,动态规划应该算是结束了,接下来应该就是回溯算法啦!还记得上学期的时候,我写了一份回溯算法求全部拓扑序列的博客,时至今日已经忘得差不多啦。不说了,每日一题,明天回溯!奥利给!