leetcode暴力屎山代码(四)——leetcode42

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

示例 1:

输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 

思路:通过left和right双指针表示接水容器的左右两个柱子。将遍历到的第一个大于0的数,作为容器的左边框,用left_flag判断是否已有左边框。如果不满足左边框的条件,则判断能否成为右边框,判断条件:1、左边框要存在,右边框不存在。2、右边框要大于等于左边框。如果左右边框都已找到,则计算装了多少水。

总结:在编写代码的时候需要考虑一种情况:当左边框已经找到的情况下,之后的柱子都比左边框短,这样根据上面的思路就无法找到一个容器。所以需要根据left是不是已经指向最后一个柱子来判断是否已经遍历完。当出现这种情况时,需要在left右边找到最大的柱子,并判断最大的柱子是否跟left相邻。如果相邻则将left有移一位,如果不是相邻则与left组成容器并计算装了多少水。依次循环至left指向最后一个柱子。

    public int trap(int[] heights) {  
        int result = 0;
        int left = 0, right = 0;
        boolean left_flag = false , right_flag = false;
        for (int i = 0; i < heights.length; i++) {
            //将遍历到的第一个大于0的数,作为容器的左边框,用left_flag判断是否已有左边框
            if(heights[i] > 0 && !left_flag) {
                left = i;
                left_flag = true;
            }
            /*
             * 如果不满足左边框的条件,则判断能否成为右边框,判断条件:
             * 1、左边框要存在,右边框不存在
             * 2、右边框要大于等于左边框
             */
            else if (heights[i] > 0 && left_flag && !right_flag && heights[i] >= heights[left] ){
                right = i;
                right_flag = true;
            }
            //如果左右边框都找到了,则计算装了多少水
            if (right_flag && left_flag){
                int h = heights[left] > heights[right]?heights[right]:heights[left];    //两个边框选最低的
                int w = right - left + 1;   //计算宽度
                int sum = h * w;    //计算一个有几个单位
                //for循环计算除了边框装了多少单位的水
                for (int j = left + 1; j <= right - 1 ; j++) {
                    sum -= heights[j];
                }
                //除去边框
                sum -= 2 * h;
                result += sum;
                left = right;   //将右边框作为新容器的左边框
                right_flag =false;
            }
            //当遍历到了最后一个,但是左边框还没到最后,则说明有可能漏了
            if (i == heights.length -1 && left < i){
                int max = heights[left + 1];
                int max_index = left + 1;
                //找到除了left最大的
                for (int j = left + 2; j < heights.length ; j++) {
                    if (heights[j] > max) {
                        max = heights[j];
                        max_index = j;
                    }
                }
                //如果最大的就是之前left的下一个,则将left右移一个。因为到这了说明后面的点没有比之前的left更小的。
                //重置left后,将i也重置,然后重新按上面的逻辑寻找容器
                if (max_index - left == 1){
                    left++;
                    i = left;

                }else{
                    //如果最大的不是left的下一个,则次最大(max_index)和left构成的容器也可以装水,计算其中的水量
                    int new_sum = (max_index - left + 1) * max;
                    for (int k = left + 1; k <= max_index - 1 ; k++) {
                        new_sum -= heights[k];
                    }
                    new_sum -= 2 * max;
                    result += new_sum;
                    left = max_index;   //将left移动到次大的index
                    i = left;   //  将i重置,继续用上面的逻辑判断后面还有没有容器
                }
            }
        }
        return result;
    }

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值