• LeetCode_Array_42. Trapping Rain Water 接雨水【双指针】【Java】【困难】


    目录

    一,题目描述

    英文描述

    中文描述

    示例与说明

    二,解题思路

    三,AC代码

    Java

    四,解题过程

    第一搏

    第二搏


    一,题目描述

    英文描述

    Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it can trap after raining.

    中文描述

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

    示例与说明

    来源:力扣(LeetCode)
    链接:https://leetcode.cn/problems/trapping-rain-water
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    二,解题思路

    核心思路:对于每一个位置i,只需要知道该位置左右两侧最高的柱子高度,即可求出该位置能存储的水量。

    一种非常巧妙的方法是:用left和right限定左右区间,maxLeft、maxRight记录遍历过程中遇到的最大值。

    height[left] <= height[right]时:

    • 若height[left] > maxLeft,则更新maxLeft的值;
    • 否则说明对于当前位置left,左右均有高度大于height[left]的柱子,只需要选择其中较矮的一个,减去height[left]即可。

    但注意!由于是左边界在向中间移动,所以左侧柱子的高度必定小于height[right]的高度!!!

    而此时maxRight不一定大于height[right](因为还没更新),所以较矮的一定是maxLeft,也就是说ans += (maxLeft - height[left]),而不是ans += (min(maxLeft, maxRight) - height[left])

    三,AC代码

    Java

    1. class Solution {
    2. public int trap(int[] height) {
    3. if (height.length <= 2) return 0;
    4. int left = 0, right = height.length - 1;// 标记左右边界
    5. int maxLeft = 0, maxRight = 0;// 记录目前遇到的最大高度,初始化为0!!!
    6. int ans = 0;
    7. while (left < right) {
    8. if (height[left] <= height[right]) {
    9. if (height[left] > maxLeft) maxLeft = height[left];
    10. else ans += (maxLeft - height[left]);// !!!到这里表示一定有右边界大于maxLeft,所以只需要取maxLeft即可,而不是取min(maxLeft, maxRight),因为maxRight可能还没来得及更新
    11. left++;
    12. } else {
    13. if (height[right] > maxRight) maxRight = height[right];
    14. else ans += (maxRight - height[right]);// !!!同上
    15. right--;
    16. }
    17. }
    18. return ans;
    19. }
    20. }

    四,解题过程

    第一搏

    数组maxLeft和maxRight分别记录从左到右、从右到左遍历过程中当前位置遇到的最大值,其中maxLeft[i]表示,从左向右遍历到 i 时,遇到的最大值,maxRight同理。

    再次遍历数组height,对每一个位置 i 计算ans += (Math.min(maxLeft[i], maxRight[i]) - height[i]);即对每一个位置 i 计算该位置可以存储的最大水量。

    1. class Solution {
    2. public int trap(int[] height) {
    3. if (height.length <= 2) return 0;
    4. int[] maxLeft = new int[height.length];// 存储从左到右中最高的柱子高度
    5. int[] maxRight = new int[height.length];// 存储从右到左中最高的柱子高度
    6. maxLeft[0] = height[0];
    7. maxRight[height.length - 1] = height[height.length - 1];
    8. for (int i = 1; i < height.length; i++) {
    9. maxLeft[i] = Math.max(maxLeft[i - 1], height[i]);
    10. }
    11. for (int i = height.length - 2; i >= 0; i--) {
    12. maxRight[i] = Math.max(maxRight[i + 1], height[i]);
    13. }
    14. int ans = 0;
    15. for (int i = 1; i < height.length - 1; i++) {
    16. ans += (Math.min(maxLeft[i], maxRight[i]) - height[i]);
    17. }
    18. return ans;
    19. }
    20. }

    额外开两个数组,空间O(n)。 

    第二搏

    其实在遍历求解过程中,只需要知道当前位置左侧最高的柱子和右侧最高的柱子高度即可。

    一种非常巧妙的方法是:用left和right限定左右区间,maxLeft、maxRight记录遍历过程中遇到的最大值。

    height[left] <= height[right]时:

    • 若height[left] > maxLeft,则更新maxLeft的值;
    • 否则说明对于当前位置left,左右均有高度大于height[left]的柱子,只需要选择其中较矮的一个,减去height[left]即可。

    但注意!由于是左边界在向中间移动,所以左侧柱子的高度必定小于height[right]的高度!!!

    而此时maxRight不一定大于height[right](因为还没更新),所以较矮的一定是maxLeft,也就是说ans += (maxLeft - height[left]),而不是ans += (min(maxLeft, maxRight) - height[left])

  • 相关阅读:
    MySQL基础语法快速上手
    【SQLServer】并行的保留线程和已使用线程
    [maven] maven 创建 web 项目并嵌套项目
    基于Python PHP+mysql的校园电脑外设的电商平台
    【LINUX】统计liunx进程的内存使用情况
    [附源码]SSM计算机毕业设计旅游管理系统JAVA
    高斯锁表导致sql报错处理
    【高级算法设计与分析】实验2:单向与双向A*搜索算法
    跨平台开发:在Linux上构建Windows应用程序
    List与数组之间的相互转换
  • 原文地址:https://blog.csdn.net/qq_41528502/article/details/125384277