青训营之攒青豆
当青训营遇上码上掘金
紧急插播,这篇文章考虑的还是浅了,看完这个请移步新文章,但一定要看完这个,这个是基本思路
最终版更新了,这个是可行解,小伙伴们移步
原题
这算是我在掘金发布的第一篇文章了,首先感谢字节的引导,让我有了学习的方向还有更好的学习资源。首先我把原题粘过来
- 现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
以下为上图例子的解析: 输入:height = [5,0,2,1,4,0,1,0,3] 输出:17 解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。
思考过程
当我第一次看到这个题的时候其实思路是不少的
- 可以选择直接看第一个元素和最后一个元素,用较小数乘宽度再将中间元素减去就可以了。但我很快就否定了这个方法,因为如果中间有比两端大的数的话,这样计算的结果就一定不正确。
- 然后我想既然1不行,我就一个一个的看,找每个元素两侧的元素,如果两侧元素都大于此元素,此元素位置处就可以放青豆。但很快我就又否定了这个方向,因为并不知道这个位置可以放多少青豆,开始我想的就是放两侧数较小那个减去此元素的高度个数的青豆例如第二个位置就放2-0=2的青豆,容易发现,此位置不止放了两个青豆,因为后面还有高度为4的元素,此位置上其实可以放4份青豆。
- 然后我想了一种与前两个都不一样的方案,我先假设是满的,即最高高度乘宽度,然后减去不该有的地方,即使用高度差乘位置差,看似好像可行,但代入给的例子中就可以发现,我并不清楚该减几份。所以这个我也很快就废弃了。
解决方案
还有好多想法我就不再多说了,大多没有出口,现在我就详细讲讲最后的解决方案。
找到最左和最右的边界值,再找到中间的最大值,找到最左与中间的小值,乘以它们的位置差,即宽度,就找到左半部分的初步青豆数,右半部分同理,找到总的初步青豆数后将除了最大高度以外的所有数都减去,得到的就是青豆数。
注意:此处的最左和最右不一定是数组的第一个和最后一个元素,因为这两个位置可能为0,青豆不会在此位置内散落,所以要从两侧向内找第一个非0值,此元素才是边界值
for (int i =0;i<arr.length;i++){//寻找最左侧元素高度和位置,最右侧同理
if (arr[i]!=0){
header = arr[i];
h_size = i;
break;
}
}
for (int i =h_size+1;i<t_size-h_size-1;i++){//冒泡排序找到中间最大元素及其位置
if (arr[i]>max){
max = arr[i];
m_size = i;
}
}
int results = (m_size-h_size-1)*(max<header?max:header)+(t_size-m_size-1)*(max<tail?max:tail);
//忽略其他元素得到的初步结果
for (int i =h_size+1;i<t_size-h_size-1;i++){//减去其他元素
if (i==m_size) continue;//最大元素位置跳过
results = results -arr[i];
}
完整的源码我已经上传到掘金了,感兴趣的可以看看
感想
虽然说这只是简简单单的一个小题目,但还是可以反映出很多东西,比如说,我思考问题的方式还又漏洞,还会犯许多小错误,逻辑能力还是不够,还有任何简单的问题都是先是实际问题转换为数学问题,最终才能得到解决方案编写代码的,所以说数学很重要。