首页 > 其他分享 >第一篇 LeetCode(42)接雨水

第一篇 LeetCode(42)接雨水

时间:2024-06-10 22:24:09浏览次数:30  
标签:leftMax 遍历 rightMax 第一篇 42 height int LeetCode Math

LeetCode(42)接雨水

力扣官网

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

img

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

基本思路:

  1. 基础解题思路:看到这道题时,应该要能够想到要遍历数组,关键是要如何遍历

遍历方法通常情况下有:单指针(从左往右或者从右往左或者二者结合),双指针(一个从左往右遍历,一个从右往左遍历),’二者结合‘的意思区别于双指针,’二者结合‘意思是一道题目里有一次遍历是从起点遍历到终点,还有一次遍历是从终点遍历到起点

  1. 那要如何统计雨水量呢?不难想到是要边遍历边统计,且是要用一个数字去减当前遍历到的柱子高度,为什么?总雨水量是柱子间能够承接的雨水量的累加和。判断柱子间能够接多少水,注意我这里用到的词是柱子间,间!!所以遍历到第i个柱子的高度(height)时,我们要用一个数字去减遍历到的第i个柱子的高度height[i]。
  2. 如何去确定这个数字是什么,是个难点!

题解:

方法一:动态规划

fig1

有没有一点思路了?用到了一个我们刚刚说的哪个遍历方法?没错,用到的是单指针,且是二者结合的方式,至于为什么,下面会说,先保留。

  1. 第一次遍历:从左往右,每次遍历到一个值时,要做的是收集遍历到当前节点时遍历过程中的最大值,即官方给的代码中的leftMax[i] = Math.max(leftMax[i - 1], height[i]);

  2. 第二次遍历:从右往左,每次遍历到一个值时,要做的是收集遍历到当前节点时遍历过程中的最大值,即官方给的代码中的rightMax[i] = Math.max(rightMax[i + 1], height[i]);

  3. 还有一次遍历,结合刚刚收集到的leftMax数组,rightMax数组,以及height数组,遍历次数是height数组的长度,每遍历到一个i,要做的是统计雨水量了,对ans进行累加了!如何累加?每遍历到一个i,都会有一个height[i],一个leftMax[i],以及一个rightMax[i],通过刚刚第一点的分析,相信已经了解到了leftMax数组的第i个元素的含义,含义是什么,是从左往右遍历height数组时,从起点到第i个元素的height数组中的最大值。rightMax数组同理。

  4. 判断柱子间能够接多少水,用的是leftMax[i]与rightMax[i]中的最小值去剪掉height[i],要理解用的这个数字是leftMax[i]与rightMax[i]中的最小值。如何理解,一个很好的方法就是实践!结合上面的图解+height数组,相信你能够理解了吧。因为是承接的水量是由两个柱子中最小的那根柱子来决定的(木桶效应)。

  5. 为什么叫动态规划,leftMax[i] = Math.max(leftMax[i - 1], height[i]);rightMax[i] = Math.max(rightMax[i + 1], height[i]);发现什么规律没有,,leftMax[i]与rightMax[i]值的确定都跟leftMax[i - 1]跟(rightMax[i + 1]有关系,所以简单理解,就是第i个值的确定与第i-1个值有关系,即为动态规划,当然,动态规划不是这个定义,我概括的比较粗糙。

    img

class Solution {
    public int trap(int[] height) {
        int n = height.length;
        if (n == 0) {
            return 0;
        }

        int[] leftMax = new int[n];
        leftMax[0] = height[0];
        for (int i = 1; i < n; ++i) {
            leftMax[i] = Math.max(leftMax[i - 1], height[i]);
        }

        int[] rightMax = new int[n];
        rightMax[n - 1] = height[n - 1];
        for (int i = n - 2; i >= 0; --i) {
            rightMax[i] = Math.max(rightMax[i + 1], height[i]);
        }

        int ans = 0;
        for (int i = 0; i < n; ++i) {
            ans += Math.min(leftMax[i], rightMax[i]) - height[i];
        }
        return ans;
    }
}

作者:力扣官方题解

方法二:单调栈

  1. 该方法同样是使用单指针的方法,但是只用了一次遍历,从左往右遍历height数组。
  2. 那么如何处理每一次遍历到的height[i]呢?入栈。入栈的数据是height数组的下标(0,1,2,3....),且并不是一开始就入栈,是要先处理一些情况,期间肯定包括怎么得到柱子间的雨水量。设计一种模式,只要栈不为空且遍历到的元素height[i]比栈顶元素大(’只要‘ 所以采用while循环),我们就删掉栈顶元素,这样子在每次遍历height数组前,栈都满足栈顶元素比上一个进栈的元素小(height[i]比栈顶元素小,不删栈顶元素,仅仅把height[i]放入栈中)。那么在遍历到height[i]比栈顶元素大时,此时就满足了两边(栈顶的上一个元素+遍历到的元素)高,中间(栈顶)低的情况了,用两边中最小的数字减掉中间(栈顶)数字,就可以得到currHeight了,再使用i - left - 1得到curWidth。二者相乘即可得到一个大的区间内雨水的承接量,注意,得到总雨水承接两要用累加。注意,这个过程要使用while操作。原因是只要满足两边高,中间低的情况,我们都要收集这个区间内的雨水承接量。while循环结束后,把下标放进栈中。
class Solution {
    public int trap(int[] height) {
        int n = height.length;
        if (n == 0) {
            return 0;
        }

        int[] leftMax = new int[n];
        leftMax[0] = height[0];
        for (int i = 1; i < n; ++i) {
            leftMax[i] = Math.max(leftMax[i - 1], height[i]);
        }

        int[] rightMax = new int[n];
        rightMax[n - 1] = height[n - 1];
        for (int i = n - 2; i >= 0; --i) {
            rightMax[i] = Math.max(rightMax[i + 1], height[i]);
        }

        int ans = 0;
        for (int i = 0; i < n; ++i) {
            ans += Math.min(leftMax[i], rightMax[i]) - height[i];
        }
        return ans;
    }
}

作者:力扣官方题解

方法三:双指针

  1. 该方法用到的是双指针。
  2. 左指针遍历到height数组的每一个元素,更新遍历到的元素中的最大值leftMax。右指针遍历到height数组的每一个元素,更新遍历到的元素中的最大值rightMax。
  3. 两种情况,如果左指针遍历到的元素比右指针遍历到的元素小height[left] < height[right],那么就要用leftMax - height[left]得到两根柱子间的雨水承接量,同时左指针右移。这里要说明的是,为什么被减数是leftMax,因为在height[left] < height[right]情况下,肯定也满足了leftMax<rightMax,前面两种方法里,都涉及到了’两边高,中间低,用两边最小的数字减去中间的数字‘,这里同理。不一样的地方在于这里的两边不是中间柱子的左右两根柱子。建议用具体的height数组自己操演一遍,加深理解。
  4. 右指针同理。
class Solution {
    public int trap(int[] height) {
        int ans = 0;
        int left = 0, right = height.length - 1;
        int leftMax = 0, rightMax = 0;
        while (left < right) {
            leftMax = Math.max(leftMax, height[left]);
            rightMax = Math.max(rightMax, height[right]);
            if (height[left] < height[right]) {
                ans += leftMax - height[left];
                ++left;
            } else {
                ans += rightMax - height[right];
                --right;
            }
        }
        return ans;
    }
}

作者:力扣官方题解

以上,是参考力扣官方解析,与自己的见解,如有错误,欢迎指正。

题外话:我觉得理解代码最好的方式是:自己举个例子,结合代码操演一遍,两遍,三遍........学习路上,希望你能发现java的魅力,并爱上java。

标签:leftMax,遍历,rightMax,第一篇,42,height,int,LeetCode,Math
From: https://www.cnblogs.com/yyydddsss/p/18240828

相关文章

  • LeetCode 974 Subarray Sums Divisible by K All In One
    LeetCode974SubarraySumsDivisiblebyKAllInOneLeetCode974能被K整除的子数组之和errosfunctionsubarraysDivByK(nums:number[],k:number):number{//-5/0/5letcount:number=0;//单个元素for(leti=0;i<nums.length;i++){......
  • C136 线段树分治 P4219 [BJOI2014] 大融合
    视频链接: P4219[BJOI2014]大融合-洛谷|计算机科学教育新生态(luogu.com.cn)#include<iostream>#include<cstring>#include<algorithm>#include<vector>#include<map>usingnamespacestd;#definels(u<<1)#definers(u<<1|......
  • Q24 LeetCode383 赎金信
    同Q23只需要先将随机字符串挨个存入hashmap中,然后循环遍历给定字符串,只要最后hashmap中size为0,即可返回true 1classSolution{2publicbooleancanConstruct(StringransomNote,Stringmagazine){34HashMap<Character,Integer>smap=newH......
  • Q23 LeetCode242 字母异位词
    1.先进行简单的字符长度判断,不相等直接返回false;2.containsKey()的使用3.在减减循环14-17行里判别key的value是否为0,要不然会报错 1classSolution{2publicbooleanisAnagram(Strings,Stringt){3if(s.length()!=t.length()){4return......
  • 每日一题(LeetCode·704)二分查找
    题目:给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。示例1:输入:nums=[-1,0,3,5,9,12],target=9输出:4解释:9出现在nums中并且下标为4示例 2:输入:num......
  • 每日一题(LeetCode 34题,在排序数组中查找元素的第一个和最后一个元素)
    题目:给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。如果数组中不存在目标值 target,返回 [-1,-1]。你必须设计并实现时间复杂度为 O(logn) 的算法解决此问题示例1:输入:nums=[5,7,7,8,8,10],......
  • Leetcode-807
    题目807.保持城市天际线难度:中等给你一座由nxn个街区组成的城市,每个街区都包含一座立方体建筑。给你一个下标从0开始的nxn整数矩阵grid,其中grid[r][c]表示坐落于r行c列的建筑物的高度。城市的天际线是从远处观察城市时,所有建筑物形成的外部轮廓。从东、......
  • Leetcode-342
    题目4的幂难度:简单给定一个整数,写一个函数来判断它是否是4的幂次方。如果是,返回true;否则,返回false。整数n是4的幂次方需满足:存在整数x使得n==4x示例1:输入:n=16输出:true示例2:输入:n=5输出:false示例3:输入:n=1输出:true提示:-231<=n<=......
  • Leetcode-42
    题目42.接雨水难度:困难给定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个单位的雨水(蓝色部......
  • Leetcode-852
    题目852.山脉数组的峰顶索引难度:简单山脉数组arrarr.length>=3存在i(0<i<arr.length-1)使得:arr[0]<arr[1]<...arr[i-1]<arr[i]arr[i]>arr[i+1]>...>arr[arr.length-1]给你由整数组成的山脉数组arr,返回任何满足arr[0]<arr[1]<...arr[......