首页 > 其他分享 >力扣 42.接雨水

力扣 42.接雨水

时间:2024-05-23 22:26:09浏览次数:10  
标签:高度 int max 42 雨水 heights 力扣 right height

题目描述:

给定 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 个单位的雨水(蓝色部分表示雨水)。 

示例 2:

输入:height = [4,2,0,3,2,5]
输出:9

题解1:按行来求,一行一行算,先计算出最高的“墙”的高度,然后从最高的那行开始遍历,对于每一行来说,比如第5行(首行是第1行),从左到右遍历一行,如果现在该行某一位置墙的高度大于等于5,我们就记录下来,假设用 l 记录,继续向后遍历,发现又出现一个墙的高度大于等于5的位置,用  r  记录下来,那么我们现在就可以确定,l 和 r之间肯定是低洼,可以蓄水的地方,并且由于我们只关心这一行,因此,蓄水的容量就是 r-l+1 。继续遍历这一行的时候,需要先将左边界 l 重置成 r,即 l  =  r,下一个低洼,就以该 l 作为新的左边界,同样的方法寻找右边界。

处理完一行之后,行数减1开始处理下一行。

class Solution {
    public int trap(int[] height) {
 int len = height.length;
        if (len <= 2) return 0;

        int max = Arrays.stream(height).max().orElseThrow(() -> new IllegalArgumentException());
        int count = 0;

        for (int h = max; h > 0; h--) {
            int l = -1;
            int r = 0;
            while (r < len) {
                if (height[r] >= h) {
                    if (l != -1) {
                        count += r - l - 1;
                    }
                    l = r;
                }
                r++;
            }
        }

        return count;
    }
}

代码解释:l 是否等于-1是用来判断现在是否已经找到了一个左边界了,寻找左边界的过程是用 r 的递增来实现的,r 找到一个边界,就会通知 l ,如果是该行第一个左边界,那么 l 是等于-1的,直接将l = r,r 继续寻找下一个边界,再次找到,又来通知 l ,但是现在发现 l 不等于 -1,说明现在找出来一对左右边界了,可以进行蓄水量计算了,计算完成之后,再将 l 置为 r,指定下一个低洼的左边界,以此类推。

说明:320/322 还是会超时,暴力解法可以不用,但是得会,其实我自己做出来的暴力解法要比这个麻烦,但是整体思路是一致的,贴在这里,留个念想,毕竟是第一次这么接近hard题的全对:

public static int trap(int[] height) {
        //首先找到最高的元素,就是循环进行次数
        int max = Arrays.stream(height).max().orElseThrow(() -> new IllegalArgumentException());
        int len = height.length;
        int count = 0;
        while (max > 0) {
            max--;
            //int arr[] = new int[len];
            List<Integer> list = new ArrayList<>();
            //从上往下
            for (int i = 0; i < len; i++) {
                /*list.add((height[i] - max + 1) > 0:1 ? 0);*/
                if((height[i] - max )>0){
                    list.add(1);
                }else{
                    list.add(0);
                }

            }
           // System.out.println("第"+max+"次循环: "+list);
            //初始化l,r
            int l = list.indexOf(1);
            int r = l+1;
            //System.out.println("初始化的l r"+l+" "+r);
            while(r<len){

                while(r<len&&list.get(r)==0)
                {
                    r++;
                }
               // System.out.println("不 "+l+" "+r);

                if(r<len) {
                    count += (r - l - 1);
                    //System.out.println("count: "+count);
                    l = r;
                    r = l + 1;
                }
            }

        }
        return count;

    }

题解2:按列求,没有按行求直观,还需要分成三种其概况讨论。涉及三个墙,当前在求的这列墙,这列墙左边最高和右边最高的墙,当往左右最高的墙中间添水的时候,当列在求的墙能蓄多少水,取决于当列以左最高的墙 和 当列以右最高的墙中较矮的一堵(木桶效应),用较矮的一堵墙减去当前在求列墙的高度就是当前列能够蓄水量。这三堵墙的关系又分成以下三种情况:

左右最高的墙中  较矮的那一堵墙高度 大于正在求的列

计算:

 

左右最高的墙中 较矮的那一堵墙高度  小于当前在求列的高度

计算:当前列没有蓄水

左右最高的墙中 较矮的那一堵墙高度 等于当前在求列的高度

计算:当前列不会蓄水

总结:只有当前列比左右最大高度中较小的那堵墙矮的时候才会蓄水。

代码实现:

public int trap(int[] heights) {
    int totalWater = 0;
    // 最两端的列不用考虑,因为一定不会有水。所以下标从 1 到 length - 2
    for (int current = 1; current < heights.length - 1; current++) {
        int leftMax = 0;
        // 找出左边最高
        for (int left = current - 1; left >= 0; left--) {
            if (heights[left] > leftMax) {
                leftMax = heights[left];
            }
        }
        int rightMax = 0;
        // 找出右边最高
        for (int right = current + 1; right < heights.length; right++) {
            if (heights[right] > rightMax) {
                rightMax = heights[right];
            }
        }
        // 找出两端较小的
        int minHeight = Math.min(leftMax, rightMax);
        // 只有较小的一段大于当前列的高度才会有水,其他情况不会有水
        if (minHeight > heights[current]) {
            totalWater += minHeight - heights[current];
        }
    }
    return totalWater;
}

题解3:针对上述按照列求,会发现有很多重复计算,主要是在,每次计算一列墙的时候,都需要去计算其左边和右边最高墙的高度,这样实际上每计算一列墙都需要循环遍历一遍整个数组,时间复杂度很大,因此考虑用一种算法实现计算每列墙左边和右边的最高墙的高度,并且通过一边循环就计算出来,用数组max_left(i)表示的就是i列以左墙的最高值,max_right(i)就是i列以右墙的最高值,考虑使用dp ,dp方程:

 max_left[i] = Math.max(max_left[i - 1], height[i - 1]);
 max_right[i] = Math.max(max_right[i + 1], height[i + 1]);

完整的代码实现:

public int trap(int[] heights) {
    int totalWater = 0;
    int n = heights.length;
    
    // maxLeft[i] 表示位置 i 左侧(不包括 i)的最大高度
    int[] maxLeft = new int[n];
    // maxRight[i] 表示位置 i 右侧(不包括 i)的最大高度
    int[] maxRight = new int[n];
    
    // 计算 maxLeft 数组
    for (int i = 1; i < n - 1; i++) {
        maxLeft[i] = Math.max(maxLeft[i - 1], heights[i - 1]);
    }
    
    // 计算 maxRight 数组
    for (int i = n - 2; i >= 0; i--) {
        maxRight[i] = Math.max(maxRight[i + 1], heights[i + 1]);
    }
    
    // 计算可以存储的水量
    for (int i = 1; i < n - 1; i++) {
        int minHeight = Math.min(maxLeft[i], maxRight[i]);
        if (minHeight > heights[i]) {
            totalWater += minHeight - heights[i];
        }
    }
    
    return totalWater;
}

标签:高度,int,max,42,雨水,heights,力扣,right,height
From: https://blog.csdn.net/qq_62622854/article/details/139133174

相关文章

  • python计算雨水含量(W)
     数据: #!usr/bin/envpython#-*-coding:utf-8-*-"""@author:Suyue@file:raincontent.py@time:2024/05/23@desc:"""importnumpyasnpimportpandasaspdimportxlwtimportmathdf1=pd.read_excel('20240510五原数浓......
  • 力扣-636. 函数的独占时间
    1.题目题目地址(636.函数的独占时间-力扣(LeetCode))https://leetcode.cn/problems/exclusive-time-of-functions/题目描述有一个单线程CPU正在运行一个含有n道函数的程序。每道函数都有一个位于 0和n-1之间的唯一标识符。函数调用存储在一个调用栈上:当一个函......
  • 力扣1542 2024.5.22
    原题网址:此处为链接个人难度评价:1700分析:很惊讶会又在力扣看到区域赛的几乎原题。此题加上一个哈希就是区域赛题目了。回文其实你只需要关注奇偶性。那么你用前缀和,维护[0:i]区间内每个数的奇偶性,此时你可以发现[0:i]和[i:j]的前缀和异或之后,为0的位就说明[i:j]内此位为偶。(也......
  • 力扣2589 5.16
    原题网址:此处为链接个人难度评价:1700分析:原本的想法是按开始时间排序后遍历,然后贪心的把下一段的和这一段的放一起,发现不够放了就把不够的算出来截为新的一段。最后发现其实有后效性。正解的贪心是:按结束时间排序后(当然是升序),贪心的把本段的都放最后。每次放的时候先检查本区......
  • 力扣-1209. 删除字符串中的所有相邻重复项 II
    1.题目题目地址(1209.删除字符串中的所有相邻重复项II-力扣(LeetCode))https://leetcode.cn/problems/remove-all-adjacent-duplicates-in-string-ii/题目描述给你一个字符串 s,「k倍重复项删除操作」将会从s 中选择 k 个相邻且相等的字母,并删除它们,使被删去的字符串的......
  • CSP历年复赛题-P1042 [NOIP2003 普及组] 乒乓球
    原题链接:https://www.luogu.com.cn/problem/P1042题意解读:分别针对11分制和21分制,输出每局比分。只需要判断一局的结束条件:得分高者如果达到11或者21,且比分间隔大于等于2分,则表示一局结束,可开始下一局,用模拟法即可解决。100分代码:#include<bits/stdc++.h>usingnamespaces......
  • 测试 width="242" height="242"
    1  width="242"height="242"         ......
  • 422是一个HTTP状态码,表示服务器理解客户端的请求,但无法处理该请求。这个状态码通常被
    422是一个HTTP状态码,表示服务器理解客户端的请求,但无法处理该请求。这个状态码通常被用于Web应用程序中的表单验证,其中服务器无法处理客户端提交的表单数据。具体来说,当一个客户端向服务器提交表单数据时,服务器首先会验证这些数据是否符合要求。如果数据验证失败,服务器会返回422......
  • 力扣刷题备忘1
    1、释放链表节点时要注意,不要出现先保存虚拟头节点,然后又释放的情况,释放后的地址不应该被使用正确写法:ListNode*dhead=newListNode(0,head);//虚拟头结点ListNode*result=dhead->next;//释放dhead之前,使用result保存deletedhead;错误写法:ListNode*result=dhea......
  • 二叉树 | 迭代法 102.二叉树的层序遍历 429. N 叉树的层序遍历 226.翻转二叉树
    leetcode102.二叉树的层序遍历题目102.二叉树的层序遍历给你二叉树的根节点root,返回其节点值的层序遍历。(即逐层地,从左到右访问所有节点)。解题思路实现代码classTreeNode:def__init__(self,val=0,left=None,right=None):self.val=valse......