积水问题(层级法)
有一组不同高度的台阶,有一个整数组数表示,数组中每个数是台阶的高度。当开始下雨(水足够的多),台阶之间的水坑会积多少水呢?
如图:数组为[0,1,2,1,0,1,3,2,1,2,1,0], 积水为5
问题分析
问题思路有两个方向:
①是每一列多少积水然后相加;
②另外就是每一层有多少积水最后相加。
由于积水取决去两边有没有台阶,所以判断每一列有多少积水,做起来相对比较复杂,而第二种分层法相对比较简单,只需要统计每一层第一个不是空台阶和最后一个不是空台阶之间的空台阶数
第一层
第一个不是0开始的是下边为1的数,而最后一个不是0的则是倒数第二个
[0,1,2,1,0,1,3,2,1,2,1,0] —去掉两边的0-----》[1,2,1,0,1,3,2,1,2,1] 中间一共有一个0(即一个空台阶),所以第一层为 1
第二层
第二层只需要把所有的数减去1,小于0的当做0处理即可
[0,1,2,1,0,1,3,2,1,2,1,0] —循环减1–》[0,0,1,0,0,0,2,1,0,1,0,0]
继续执行第一个不是0开始数和最后一个不是0的则是倒数第二个
[0,0,1,0,0,0,2,1,0,1,0,0] —去掉两边的0-----》[1,0,0,0,2,1,0,1] 中间一共有4个0(即一个空台阶),所以第一层为 4
第三层
第三层只需要把所有的数减去2,小于0的当做0处理即可
[0,1,2,1,0,1,3,2,1,2,1,0] —循环减2–》[0,0,0,0,0,0,1,0,0,0,0,0]
继续执行第一个不是0开始数和最后一个不是0的则是倒数第二个
[0,0,0,0,0,0,1,0,0,0,0,0] —去掉两边的0-----》[1] 中间没有0(没有空台阶),所以第三层为0
go代码实现
func main() {
var s = []int{0,1,2,1,0,1,3,2,1,2,1,0}
var total = 0
max := max(s)//最高有多少层
for i := 0; i < max; i++ {
sl := make([]int, 0)
for _, v := range s {
//每一层执行减去下面的层数
tmp := v - i
if tmp < 0 {
tmp = 0
}
sl = append(sl, tmp)
}
preIndex := preZero(sl)//数组前面第一个不是0下标位置
sufIndex := sufZero(sl) //数组最后倒数不是0下标位置
total += countZero(sl[preIndex:sufIndex])//每一层中间0全部加起来
}
fmt.Println(total)
}
//统计一共有多少个0
func countZero(ssss []int) int {
var count = 0
for _, v := range ssss {
if v == 0 {
count++
}
}
return count
}
//数组的第一个不是0下标
func preZero(ss []int) int {
var preZero = 0
for k, _ := range ss {
if ss[k] == 0 {
preZero++
} else {
break
}
}
return preZero
}
////数组倒数不是0下标位置
func sufZero(ss []int) int {
var sufZero int = len(ss)
var lens = len(ss)
for k, _ := range ss {
if ss[lens-k-1] == 0 {
sufZero--
} else {
break
}
}
return sufZero
}
//数组最大数
func max(l []int) (max int) {
max = l[0]
for _, v := range l {
if v > max {
max = v
}
}
return
}
php代码实现
<?php
$arr = array(0,1,2,1,0,1,3,2,1,2,1,0);
$num = max($arr);
$a = 0;
for ($i = 0; $i < $num; $i++) {
$str = implode('', $arr);
$str = trim($str, 0);
$num_zero = substr_count($str, "0");
$a += $num_zero;
array_walk_recursive($arr,
function (&$v, $k) {
$v -= 1;
if ($v <= 0) {
$v = 0;
}
});
}
var_dump($a);
die;
?>