接雨水算法题

4 篇文章 0 订阅
博客介绍了如何解决接雨水问题,通过分析得出关键策略是找到最高柱子并计算其两侧能储存雨水的柱子高度差。代码实现中,首先找到最高柱子,然后分前后两段寻找次高的柱子,计算两者之间的柱子所能储存的雨水。最终递归累计所有水坑的储水量。博客还提到边界处理和优化空间,鼓励读者提出更多解题思路。
摘要由CSDN通过智能技术生成

前两天,听同事说什么接雨水问题。之前没看过,出于好奇,“力扣”上搜索了一下。读了一下题目,思索了一会,嗯,还算可以。“不传谣,不信谣。”不难,也不简单,比较适中。

题目:

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

分析:

1.能储水的地方都是“两端高,中间低”的特点。

2.每个坑能储水的高度,都是以两边最低的为准。

3.假设每个储水的坑,以最高的为一边,另一边需要

分别在这最高边的两侧找仅次于他的高度边。标记两个坑后,在以次边向后延伸,找相对于当前边的次边。标记坑后,以此类推。走到最后的边界为止。

4.当前边与次边形成的坑,必须不相邻,否则存不住水。

思路:

通过以上分析,上手搞一下。简单说一下代码流程。

1.首先找到最高的柱子Max,划分为两段分别找水坑。

2.分别向前后寻找,仅次于Max的的柱子。找到后并标记Max1,

(相邻的话不计为Max1,跳过计算,并把当前的Max1记为Max,继续寻找。)

记录Max与Max1中间的柱子。Max与Max1中间的水柱机位Hn,水坑储水总量为,

Max1 - H1到Max-Hn的和。

3.递归累计。

代码:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

public class TheRainTest {
    public static void main(String[] args) {
        int[] height = {5,8,9,4,9,6,1,4};
        System.out.println(new TheRainTest().trap(height));
    }
    public int trap(int[] height) {
        //判断是否可以储水
        if(Objects.isNull(height) || height.length == 0 || height.length == 1 || height.length == 2){
            return 0;
        }

        //regin max最高值,maxIndex最高值下标(寻找最高柱子)
        int max = 0,maxIndex = 0;
        for(int i = 0 ; i < height.length; i++){
            if(max < height[i]){
                max = height[i];
                maxIndex = i;
            }
        }
        if(max == 0){
            return 0;
        }
        //endregion

        List<int[]> befores = new ArrayList<>();
        List<int[]> afters = new ArrayList<>();
        //记录前半段每个水坑的柱子
        beforeCollect(height,maxIndex,befores);
        //记录后半段每个水坑的柱子
        afterCollect(height,maxIndex,afters);

        //总面积
        int sum = sumBefore(befores) + sumAfter(afters);

        return sum;
    }

    /**
     * 计算每段坑的储水总和
     * @param befores 最高柱子前半段的坑段
     * @return 前半段储水和
     */
    public int sumBefore(List<int[]> befores){
        if(befores.size() == 0){
            return 0;
        }
        int sum = 0;
        for(int[] tempCollect : befores){
            int max = tempCollect[0];
            for(int i = 1; i < tempCollect.length; i++){
                sum += max - tempCollect[i];
            }
        }
        return sum;
    }
    /**
     * 计算每段坑的储水总和
     * @param afters 最高柱子后半段的坑段
     * @return 后半段储水和
     */
    public int sumAfter(List<int[]> afters){
        if(afters.size() == 0){
            return 0;
        }
        int sum = 0;
        for(int[] tempCollect : afters){
            int max = tempCollect[tempCollect.length-1];
            for(int i = tempCollect.length-2; i >= 0; i--){
                sum += max - tempCollect[i];
            }
        }
        return sum;
    }

    /**
     * 收集最高峰前,坑最大的区间段
     * @param height 总段
     * @param maxIndex 最大的柱子高
     * @param befores 记录每段的柱子
     */
    public void beforeCollect(int[] height,int maxIndex, List<int[]> befores){
        if(maxIndex == 0){
            return;
        }
        int tempMax = 0,tempMaxIndex = 0;
        for(int i = 0; i < maxIndex; i++){
            if(height[i] >= tempMax){
                tempMaxIndex = i;
                tempMax = height[i];
            }
        }
        if(tempMax == 0){
            return;
        }
        if(maxIndex - tempMaxIndex > 1) {
            int[] segment = Arrays.copyOfRange(height, tempMaxIndex, maxIndex);
            befores.add(segment);
        }
        beforeCollect(height,tempMaxIndex,befores);
    }
    /**
     * 收集最高峰前,坑最大的区间段
     * @param height 总段
     * @param maxIndex 最大的柱子高
     * @param afters 记录每段的柱子
     */
    public void afterCollect(int[] height,int maxIndex, List<int[]> afters){
        if(maxIndex == height.length - 1){
            return;
        }
        int tempMax = 0,tempMaxIndex = 0;
        for(int i = maxIndex+1; i < height.length; i++){
            if(height[i] >= tempMax){
                tempMaxIndex = i;
                tempMax = height[i];
            }
        }
        if(tempMax == 0){
            return;
        }
        if(tempMaxIndex - maxIndex >1){
            int[] segment = Arrays.copyOfRange(height,maxIndex+1,tempMaxIndex+1);
            afters.add(segment);
        }
        afterCollect(height,tempMaxIndex,afters);
    }

}

总结:

        中间没有考虑到边界,修改了两次通过了“力扣”的校验。其中,还有可以根据时间和空间改进的地方。或者换一个思路解决。自我觉得,如果我再考虑的话,还是需要找到最高的柱子来解题。小伙伴可以多多提意见,相互学习,开阔思路。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值