求解数组中左右较小的最大值,装水问题

题目描述

给你一个数组,数组中的每个数代表一堵墙的高度,两堵墙中的凹地区会存有水,请你求出一共有多少格水?
例如,数组arr=3,2,4,1,5
则图中红色部分共装了1+3共4格水
在这里插入图片描述

思路分析

此题,最先容易想到的思路就是,寻找凹处,然后把凹处挨个计算,但是,这个思路有个问题,那就是,如果你已经挨个统计了很多凹处的水,此时,突然发现,左右各出现一个特别高的墙,相当于中间部分全是凹处,此时,前面凹处的计算就不对了。
因此,此题在思路上,确实有一定难度,因此,类似于洗衣机问题,如果一个题目的思路无从下手,可以考虑站在某一个个体的视角考虑问题。
就像此题,我们可以统计出每一个墙上面的水有多少格,然后最终汇总,就是整体有多少格水,而每一个具体的墙上面的水,可以通过其左右区间内的最大值来寻找,左右区间的最大值中较小的那个,就是木桶原理中的门槛,超过部分会流走。因此,这个位置上面的水的多少就是左右区间的最大值中较小值,减去当前的高度。
如何代码实现统计左右区间的最大值呢?
最笨方法,原地左右遍历,时间复杂度O(n^2)。
优化方法,申请两个辅助数组,一个数组保存当前位置左边最大值,一个数组保存当前位置右边最大值,先遍历两边,更新左右两边最大值的辅助数组。然后,再遍历原数组,每遍历到一个位置,就去这两个辅助数组中查当前位置左右的最大值,总共遍历三遍,时间复杂度O(n),空间复杂度O(n)

最优解法,设定两个指针,一个指向最左边,一个指向最右边,设定两个变量,分别记录左右的最大值。然后,左右第一个数,分别赋值给左右的最大值变量,因为边界上的值不可能产生水,此时,左右最大值的区间其实还都只有边界这一个数,对吧?然后,找出左右最大值中较小的那个,指向他的指针向中间移动,来到下一个位置,然后,对比这个位置是否能产生水,如果这个数大于临近的那个最大值,则不产生水,同时,最大值更新为他,如果小于,则产生水,最大值不更新。当左右指针碰面时结束。
为什么这样操作?
首先,为什么要找左右区间最大值中较小的那个?因为,他就是临近位置的左右最大值中较小的。因为指针是从两端开始的,此时,找到较小的最大值临近的位置,这个位置上,另一边区间的最大值,肯定大于临近的最大值。因为无论另一边最大值往后遍历的时候如何更替,反正只可能变大,不可能变小,但是,此时就已经比他临近的这边的最大值还大了,因此,这个临近的最大值,就是这个位置两边区间内较小的最大值。

代码

    public static int f(int[] arr){
        int leftMax=arr[0];
        int rightMax=arr[arr.length-1];
        int left=0;
        int right=arr.length-1;
        int sum=0;

        while (left<right){
            if(leftMax<rightMax){
                left++;
                if(leftMax>arr[left]){
                    sum+=leftMax-arr[left];
                }else {
                    leftMax=arr[left];
                }
            }else {
                right--;
                if(rightMax>arr[right]){
                    sum+=rightMax-arr[right];
                }else {
                    rightMax=arr[right];
                }
            }
        }
        return sum;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值