当青训营遇上码上掘金,本人选择的主题为主题四“攒青豆”。
一、题目内容介绍
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
二、具体算法思想
找到最高峰。分别从左右遍历。正向遍历,当下一个峰小于当前峰,可以接青豆,同理反向遍历
- 我们以列为单位去分割总任务,最后要求总的接水量,其实就是把每一列的接水量加起来的总和。
- 要想要能接水,那么左边的柱子高度必须严格大于该列的高度,右边的柱子也必须严格大于该列高度(即:左右与该列要能形成凹槽)。 此时栈内是递减的,下一个将要进站的元素是下标为6的元素(高度为1),如果它直接进栈就会破坏单调栈,因此,需要元素出栈,那么下标为5的元素就要出栈,在它出栈的同时,我们可以直接计算出这个出栈的元素可以收集的雨水量,但是有一个注意点是,在这里每个小凹槽按行收集比按列收集要方便。 首先,我们要记得我们维护的栈是一个非递增的栈。
三、代码实现部分
采用JAVA语言编写
int trap(int[] h) {
int sum = 0;
int l=0;
int[] f=new int[h.length];
int[] aar=new int[h.length];
if (h.length<2) {//长度小于2,接不了
return 0;
}
for (int i = 0; i <h.length; i++) {//找到最高峰
aar[i]=h[i];
}
int aar_Max = aar[0];
for(int i=0;i<aar.length;i++){
if(aar[i]>aar_Max){//
aar_Max=aar[i];
l = i;
}
}
for (int i = 1; i <l; i++) {//正向遍历
if(h[i-1]>h[i]){
f[i]=h[i-1]-h[i];
h[i]=h[i-1];
}else {
f[i]=0;
}
}
for (int i = h.length-2; i > l; i--) {//反向遍历
if(h[i+1]>h[i]){
f[i]=h[i+1]-h[i];
h[i]=h[i+1];
}else {
f[i]=0;
}
}
for(int i=0;i<h.length;i++){
sum = sum+ f[i];
}
return sum;
}
我们其实在总体遍历的过程中是按列遍历的,然后不断找到可以接水的凹槽,对于每个凹槽我们其实是按行的方式去计算出其盛水量的,我们在出栈的过程中其实是不断找寻左挡板的过程,这过程中会遇见接不了水的情况(我们也可以认为接水量为0,依旧把他加入最后结果中)。
四、个人总结
通过参与此次活动,让我对代码的编写有了更加清晰和深刻的理解。对后端这个岗位有了更清晰的了解。了解到了后端发展的历程,扩宽了我的知识面。