攒青豆
当青训营遇上码上掘金
题目介绍
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
以下为上图例子的解析:
输入:height = [5,0,2,1,4,0,1,0,3]
输出:17
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。
思路分析
本题出处源于LeetCode42.接雨水,共有两种解题方法,分别为递减栈和双指针法
本题思路与其相同,可以使用动态规划
对数组中的所有元素进行预处理:首先从两边开始向中间遍历,同时分别记录,左边遍历得到的最大值,右边遍历得到的最大值。从右往左遍历找到每一根柱子右侧最高的柱子,再从左往右遍历找到每一根柱子左侧最高的柱子。左边的豆子等于左边的最大值减去当前遍历的值,右边的豆子等于右边的最大值减去当前的遍历值对于每一柱子,能攒青豆的量就是左右两侧最高柱子的最小值与当前柱子的高度的差值,将所有能接住的青豆数量相加即为最终结果。
代码实现
#include<bits/stdc++.h>
using namespace std;
int main() {
vector<int> hight;
hight = { 5,0,2,1,4,0,1,0,3 };
vector<int> left = vector<int>(hight.size(), 0);
vector<int> right = vector<int>(hight.size(), 0);
int curMaxHight = hight[0];
for (int i = 0; i < hight.size(); i++) {
curMaxHight = max(curMaxHight, hight[i]);
left[i] = curMaxHight;
}
curMaxHight = hight[hight.size() - 1];
for (int i = hight.size() - 1; i >= 0; i--) {
curMaxHight = max(curMaxHight, hight[i]);
right[i] = curMaxHight;
}
int sum = 0;
for (int i = 0; i < hight.size(); i++) {
int canFillHight = min(left[i], right[i]);
sum += canFillHight - hight[i];
}
cout<<sum;
}
总结
动态规划算法是通过拆分问题,定义问题状态和状态之间的关系,使得问题能够以递推(或者说分治)的方式去解决。 动态规划算法的基本思想与分治法类似,将待求解的问题分解为若干个子问题(阶段),按顺序求解子阶段,前一子问题的解,为后一子问题的求解提供了有用的信息。在求解任一子问题时,列出各种可能的局部解,通过决策保留那些有可能达到最优的局部解,丢弃其他局部解。依次解决各子问题,最后一个子问题就是初始问题的解。