题目:力扣https://leetcode-cn.com/problems/trapping-rain-water/
class Solution {
public int trap(int[] height) {
int len = height.length;
int[] leftMax = new int[len];
int[] rightMax = new int[len];
int top = 0;
int sum = 0;
for(int i=0;i<len;i++){
if(height[i]>top){
top = height[i];
}
leftMax[i] = top;
}
top = 0;
for(int i=len-1;i>=0;i--){
if(height[i]>top){
top = height[i];
}
rightMax[i] = top;
}
for(int i=0;i<len;i++){
sum += (Math.min(leftMax[i],rightMax[i])-height[i]);
}
return sum;
}
}
思路:动态规划,有时候觉得难以理解,但是真正理解之后,就会觉得动态规划其实并没有想象中那么难。 动态规划的四个步骤:
(1)将原问题分解为子问题——将求“接雨水量”的问题转化为 从左往右求对应位置最大值(leftMax) 和 从右往左求对应位置最大值(rightMax)两个子问题。
(2)确定状态——每个位置可以蓄水的量称为该位置的“状态”。
(3)确定一些初始状态(边界状态)的值——每个位置中leftMax和rightMax的较小值与该位置柱子高度hight的差 为初始状态的值。
(4)确定状态转移方程——将每个位置可以蓄水的量求和的公式为该题状态转移方程(sum += (Math.min(leftMax[i],rightMax[i])-height[i]);)。
⚠能用动规解决的问题的特点:1) 问题具有最优子结构性质。如果问题的最优解所包含的子问题的解也是最优的,我们就称该问题具有最优子结构性质。2) 无后效性。当前的若干个状态值一旦确定,则此后过程的演变就只和这若干个状态的值有关,和之前是采取哪种手段或经过哪条路径演变到当前的这若干个状态,没有关系。
1.准备阶段。声明变量len表示hight[]数组的长度;提前声明好leftMax[]和rightMax[]两个数组,后续分别用于存储从左至右数遍历的各个位置对应的最大值和从右往左数遍历的各个位置对应的最大值;声明一个top,是用于记录当前位置最大值,默认值为0;sum是每个位置蓄水量的总和,默认值为0。
int len = height.length;
int[] leftMax = new int[len];
int[] rightMax = new int[len];
int top = 0;
int sum = 0;
2.从左往右遍历,将各位置对应的最大值填入数组中。
for(int i=0;i<len;i++){
if(height[i]>top){
top = height[i];
}
leftMax[i] = top;
}
3.重置top的值为0。从右往左遍历,将各位置对应的最大值填入数组中。
top = 0;
for(int i=len-1;i>=0;i--){
if(height[i]>top){
top = height[i];
}
rightMax[i] = top;
}
4.遍历height[]数组,根据公式求出每个位置可以蓄水的量,再将其求和得到sum。
for(int i=0;i<len;i++){
sum += (Math.min(leftMax[i],rightMax[i])-height[i]);
}
5.当所有位置可蓄水量都加起来之后,sum就是题目所求的答案,返回即可。
return sum;