「青训营 X 码上掘金」主题创作活动-主题4

81 阅读2分钟

「青训营 X 码上掘金」主题创作活动-主题4

当青训营遇上码上掘金

主题4 攒青豆

问题

现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)

攒青豆.png

 输入:height = [5,0,2,1,4,0,1,0,3]  
 输出:17  
 解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。

思路

这道题目其实就是“接雨水”的翻版,只是把雨水换成了青豆。本题有两种解法:动态规划和单调栈。本文我将介绍动态规划法。

动态规划采用按列计算的方法,如果按照列来计算的话,宽度一定是1了,再把每一列的青豆的高度求出来就可以了。

当前列青豆值:min(左边柱子的最高高度,记录右边柱子的最高高度) - 当前柱子高度。

把每一个位置的左边最高高度记录在一个数组上(maxLeft),右边最高高度记录在一个数组上(maxRight)。这样就避免了重复计算,这就用到了动态规划(每一个状态一定由上一个状态推导出来)。

 leftMax[i] = max(height[i], leftMax[i - 1]);
 rightMax[i] = max(height[i], rightMax[i + 1]);

最后将每一列青豆值为正的值进行累加,得到最终能接到的青豆总数。

具体代码实现如下:(注意在读取输入时是无限循环,利用cin.get()函数读取回车结束输入

 #include <iostream>
 #include <vector>
 ​
 using namespace std;
 ​
 int getPeas(vector<int>& height)
 {
     int size = height.size();
     int res = 0;
     vector<int> leftMax(size, 0);
     leftMax[0] = height[0];
     vector<int> rightMax(size, 0);
     rightMax[size - 1] = height[size - 1];
     
     // 记录左边柱子的最高高度
     for (int i = 1; i < size; ++i)
     {
         leftMax[i] = max(leftMax[i - 1], height[i]);
     }
     // 记录右边柱子的最高高度
     for (int i = size - 2; i >= 0; --i)
     {
         rightMax[i] = max(rightMax[i + 1], height[i]);
     }
     
     // 计算青豆总数
     for (int i = 0; i < size; ++i)
     {
         int s = min(leftMax[i], rightMax[i]) - height[i]; // 每一列的青豆值
         if (s > 0) res += s;
     }
     return res;
 }
 ​
 int main()
 {
     vector<int> height;
     int num = 0;
     // 注意在读取输入时是无限循环,利用cin.get()函数读取回车结束输入
     while (1)
     {
         cin >> num;
         height.push_back(num);
         if (cin.get() == '\n')break;
     }
 ​
     int res = getPeas(height);
     cout << res << endl;
 ​
     system("pause");
     return 0;
 }