题源:
这是我在某次比赛中的比赛题,具体什么比赛忘了。。。
题意:
如图有一堆方块,现在下雨了,方块不会被冲走,方块与方块之间的凹槽里会接住雨水,现在雨下的足够大,保证可以把所有的凹槽填满,不会有雨水外溅,问可以接到多少雨水(单位:块)
输入方块的数量的数组n,n[i]代表第i列方块的数量。
输出雨水所占方块数
样例:
输入1,3,2,0,2,1,2
输出3
解释:
第4列 和 第6列 会一共存雨水 3个方块,如图
解析:
首先,要明白的是两个高的柱子中间会积水 这里分三种情况,我举几个例子
- 理想情况
2,0,1,3这种情况下是理想的情况,2和3是高柱子,中间积水量是高柱子的 偏小值(2) 减去中间每列的块数之和———min(2,3)=2,2-0 + 2-1=3,这种情况需要找出高柱子,然后减去中间每列的块,然后加和。
高柱子怎么找呢?两边的数小于中间的数就行了?看着好像是的,但情况没那么简单,我们看下一种情况
-
高柱子重复
2,2,2,1,3,3,3这种情况有重复的高柱子,我的思路是将连续的高柱子看为一个整体,简而言之,就是连续的高柱子是没有意义的,可以直接变成一个高柱子———2,1,3,因为一样高的高柱子并不存水。 -
高柱子判断条件的特例
9,0,2,0,6,1,8这种情况下看似9,2,6,8都是高柱子,但是实际上呢?我们看图,可以发现2和6并没有起到高柱子那种把水分开的作用
答案:
(可在评论区说出你的思路,大家一起讨论,我的答案也不一定对,大家一起学习)
这里我拿一个数组 1,4,4,2,9,0,1,0,6,1,8 来说明我的思路
//自定义的一个类,用来记录这一列的块数和在数组中的位置
class High(var value: Int = 0, var index: Int = 0)
fun rain(intArray: IntArray):Int {
var count = 0
val highList = ArrayList<High>()
for (i in intArray.indices) {
//先判断当前数是不是在尖尖上(左右都<=他,就表示他在尖尖上,比如21的2,131的3,444的4,当然了最左边和最右边的数我默认取了0作为边界值)
if ((intArray[i] >= if (i == 0) 0 else intArray[i - 1]) && intArray[i] >= if (i == intArray.lastIndex) 0 else intArray[i + 1]) {
//当他在尖尖上时,我需要判断上一个高柱子在高柱子list里面是不是比两边的都要矮(list里面是9,1的时候,我判断到6,就会看看上一个数1,他比前面的数以及刚得出的高柱子都要矮,所以要替换他)
if (if (highList.size > 1) highList.last().value >= highList[highList.lastIndex - 1].value && highList.last().value >= intArray[i] else true) {
highList.add(High(intArray[i], i))
} else {
highList[highList.lastIndex] = High(intArray[i], i)
}
}
}
//最后遍历并得到最终的雨水总数
var nowHighValue: Int
for (j in highList.indices) {
if (j != highList.lastIndex) {
nowHighValue = min(highList[j].value, highList[j + 1].value)
for (k in highList[j].index + 1 until highList[j + 1].index) {
count += nowHighValue - intArray[k]
}
}
}
return count
}