【算法练习】 暴力/备忘录/双指针 lc42. 接雨水

前言

大家好,今天是@LetItbeSun 坚持每日两题的第19天。(😀

这个题目是学习labuladong的高频面试题,这个题目的形式不常见,所以我也没有什么思路,是看了题解之后理解的

参考链接:https://mp.weixin.qq.com/s?__biz=MzAxODQxMDM0Mw==&mid=2247484482&idx=1&sn=9503dae2ec50bc8aa2ba96af11ea3311&chksm=9bd7fa4aaca0735c37ab72b40f5594def9f4f8ad76df4450be0c8ae1cdc2e0105a3fce1bc502&scene=178&cur_album_id=1318896187793260544#rd

 

题目

42. 接雨水

难度困难2139

给定 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

 

提示:

  • n == height.length
  • 0 <= n <= 3 * 104
  • 0 <= height[i] <= 105

 

思路

总结来说就是短板思想,就是对于每一个height[i]考虑它左边最高的板子和右边最高的板子,而height[i]能装的雨水=min(leftmax,rightmax)-height[i]

思路确定,接下来就是实现方法。

我们发现解决这个问题的关键就是求每个height[i]的leftmax和rightmax

方法一  暴力枚举

这个方法没什么说的就是对每个heght[i]都暴力枚举找到它的leftmax和rightmax  时间复杂度O(N^2)

方法二  备忘录

对于方法一的改进,方法二就是用空间换时间,建立leftmax和rightmax分别在O(N)时间内计算出它们的值。

   int trap(vector<int>& height) {
        //备忘录解法
        int n=height.size();
        //注意空集的时候返回
        if(n==0){
            return 0;
        }
        int ans=0;
        vector<int> lmax(n,0),rmax(n,0); //lmax[i]表示h{0..i]中最高的  rmax[i]表示h[i...n-1]中最高的
        lmax[0]=height[0];
        rmax[n-1]=height[n-1];
        for(int i=1;i<n-1;i++){
            lmax[i]=max(height[i],lmax[i-1]);
        }
        for(int i=n-2;i>=1;i--){
            rmax[i]=max(height[i],rmax[i+1]);
        }
        for(int i=1;i<n-1;i++){
            ans+=min(rmax[i],lmax[i])-height[i];
        }
        return ans;
    }

方法三  双指针

从两头开始用双指针left、right,对于这两个指针指到的left、right

图片

此时的l_maxleft指针左边的最高柱子,但是r_max并不一定是left指针右边最高的柱子,这真的可以得到正确答案吗?

其实这个问题要这么思考,我们只在乎min(l_max, r_max)。对于上图的情况,我们已经知道l_max < r_max了,至于这个r_max是不是右边最大的,不重要,重要的是height[i]能够装的水只和l_max有关。 

 l_max < r_max的情况,我们等于知道了右边的板子有比lmax还大的,根据短板决定,所以height[i]能够装的水就和l_max有关,

而l_max也正好就是left指针左边最高的柱子,同理right指针也一样。

int trap(vector<int>& height) {
       //双指针法
       int n=height.size();
      if(n==0){
          return 0;
      }
       int left=0,right=n-1;
       int lmax=height[0],rmax=height[n-1];
       int ans=0;
       while (left<=right){
           //更新lmax rmax
           lmax=max(height[left],lmax);
           rmax=max(height[right],rmax);
           //左边的短板就累加left所在的height  右边的短板就累加right所在的height
           if(lmax<rmax){  //右边至少有比lmax高的板
               ans+=lmax-height[left];
               left++;
           }else{
               ans+=rmax-height[right];
               right--;
           }
       }
       return ans;
   }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值