前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >LeetCode 图解 | 42. 接雨水

LeetCode 图解 | 42. 接雨水

作者头像
五分钟学算法
发布2020-05-19 17:22:43
9690
发布2020-05-19 17:22:43
举报
文章被收录于专栏:五分钟学算法五分钟学算法

作者:ioc

今天的题目来源于 LeetCode 中第 42 题:接雨水,hard 级别,目前通过率 50.8% 。

题目描述:

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

示例:

代码语言:javascript
复制
输入: [0,1,0,2,1,0,1,3,2,1,2,1]
输出: 6

题目分析:

通过题意,一个“凹槽”可以存储的雨水的容量取决于它前后的柱子。

解法一

仔细想想,其实这跟木桶原理是有相似的地方的,针对每一个柱子,我们需要往前看和往后看,分别找出当前柱子前面最高的柱子和后面最高的柱子。

这里有三种情况我们需要了解:

  • 当前柱子小于前后两个柱子中最矮的那个

当前位置可以存储的雨水容量 = leftMax - curr = 1

  • 当前柱子等于前后两个柱子中最矮的那个

当前位置可以存储的雨水容量为0

  • 当前柱子大于前后两个柱子中最矮的那个

因为curr < leftMax,所以当前位置无法存储雨水

参考代码

代码语言:javascript
复制
public int trap02(int[] height) { 
    int sum = 0;   
    //最两端的列不用考虑,因为一定不会有水。所以下标从 1 到 length - 2    
    for (int i = 1; i < height.length - 1; i++) { 
        int max_left = 0;       
        //找出左边最高        
        for (int j = i - 1; j >= 0; j--) {  
            if (height[j] > max_left) {  
                max_left = height[j];  
            }       
        }        
        int max_right = 0;       
        //找出右边最高       
        for (int j = i + 1; j < height.length; j++) { 
            if (height[j] > max_right) {  
                max_right = height[j];   
            }       
        }       
        //找出两端较小的       
        int min = Math.min(max_left, max_right); 
        //只有较小的一段大于当前列的高度才会有水,其他情况不会有水  
        if (min > height[i]) { 
            sum = sum + (min - height[i]);       
        }   
    }   
    return sum;
}

复杂度分析

  • 时间复杂度:O(n^2)
  • 空间复杂度:O(n^2)

那么有没有更好的办法来解决这个问题?

解法二:双指针

下面的方法巧妙的使用了双指针来解决问题:

与上述解法的思路大致是相同的,都是单个地求出当前墙可以存储雨水的容量;这种解法也是非常的巧妙,是在浏览解题区的时候碰见的,大佬还做了视频(链接放在文末),讲解的非常清楚,我大概用自己的思路来作一文字叙述:

既然使用的是twoPointers的思路,那么我们需要分别从数组的最前面和最后面开始,这两个指针是互不影响,都是各走各的,但是如何确定当前指针走过的地方能存放多少雨水量呢?

这个时候,我们就需要两块挡板leftMaxrightMax,这两块挡板最开始都是挡在最外面的墙边,随着两个指针前进,leftMax代表的是left走过的路中最高的墙,rightMax同理。

那么如何计算雨水量呢?

比较左右两个挡板的高度,然后根据两个挡板各自的指针配合计算。

  • 如果左边挡板的高度小于右边的挡板高度,那么左边指针之前的雨水量取决于leftMax和height[left]的大小关系,如果前者大于后者,那么容量等与前者减去后者;反之,容量为0(可以参考解法一中的图来理解)
  • 如果左边挡板的高度大于等于右边挡板的高度,与上一种情况基本相同,只不过是求的右边的雨水量。
  • 在每次移动指针之后,我们要将挡板更新到最大值。

其实道理也是比较简单,用宏观的思维去看待整个问题,最起码先保证两边的墙的高度(两块挡板),然后依次去到其中各个墙之间能装多少雨水的问题上。(求每次更新最高的挡板和指针指向的墙之间可以存储的雨水量)

参考代码

代码语言:javascript
复制
public int trap(int[] height) {
    if (height.length == 0) return 0;
    int left = 0;
    int right = height.length-1;
    int leftMax = 0;
    int rightMax = 0;
    int result = 0;
    while (left <= right) {
      if (leftMax < rightMax) {
        result += leftMax - height[left] > 0 ?
            leftMax - height[left] : 0;
        leftMax = Math.max(leftMax, height[left]);
        left++;
      } else {
        result += rightMax - height[right] > 0 ?
            rightMax - height[right] : 0;
        rightMax = Math.max(rightMax, height[right]);
        right--;
      }
    }
    return result;
  }

复杂度分析

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-05-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 五分钟学算法 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 题目描述:
  • 题目分析:
    • 解法一
      • 参考代码
        • 复杂度分析
          • 解法二:双指针
            • 参考代码
              • 复杂度分析
              相关产品与服务
              对象存储
              对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档