积水问题(层级法)

积水问题(层级法)

有一组不同高度的台阶,有一个整数组数表示,数组中每个数是台阶的高度。当开始下雨(水足够的多),台阶之间的水坑会积多少水呢?
如图:数组为[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;
?>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值