zoukankan      html  css  js  c++  java
  • LeetCode 笔记系列12 Trapping Rain Water [复杂的代码是错误的代码]

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

      For example, 
      Given [0,1,0,2,1,0,1,3,2,1,2,1], return 6.

    The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped. Thanks Marcos for contributing this image!

    例如给出上图中的黑色部分(数组表示),让你求出蓝色部分。

    这也是个神题。。。当然对小白我来说。

    想了半天,是不是遍历数组呢,然后依次计算当前bar构成的container大小。问题在于,这个方法要考虑的边界条件太多了。写了一个很复杂的算法,还用到了stack来记录碎片的蓝色部分,结果最后还是miss很多情况。

    后来想了一个复杂度比较高的但是代码看来了比较简单的算法。觉得简直要被BS屎了。但是还是记录下来以村托牛人的牛。

    想的方法我取名叫俄罗斯方块法,为啥,你马上就晓得鸟。

    把上面的图图,instead of看成一个个柱子,我看成一排排的方块。

    然后,对每一行,我数数有多少蓝色的方块,累加起来,不就是总共的蓝色部分了么。

    这个复杂度有点高,取决与最大的元素的值*O(n)。

    解法一:

     1 public static int trap(int[] A){
     2         int i = 0;
     3         int j = A.length - 1;
     4         int sumArea = 0;
     5         while(i + 1 < j){
     6             //首先找到两边都不是0的位置
     7             while(A[i] <= 0 && i < j)i++;
     8             while(A[j] <= 0 && i < j)j--;
     9             //然后数数当前行有多少蓝色方块,也是就0的个数啦。
    10             //同时记录最小值
    11             int min = Integer.MAX_VALUE;
    12             for(int k = i; k < j;k++){
    13                 if(A[k] == 0) sumArea += 1;
    14                 if(A[k] < min) min = A[k];
    15             }
    16             //为记录下一行做准备,消除俄罗斯方块。。。。
    17             int step = Math.max(min, 1);
    18             for(int k = i; k <= j; k++){
    19                 if(A[k] > 0)A[k]-= step;
    20             }
    21         }
    22         return sumArea;
    23     }
    View Code

    然后大集合就可耻地潮湿了。

    leetcode的牛人是怎么做的呢?人家不仅有O(n)的解法,而且constant space。膜拜。

    首先,找到最高的一个柱子,例如例子中的3。

    然后遍历左半边。从i=0开始靠近mid,遍历过程中维护一个curHeight,表示这当前遇到的最大的height值;如果当前的bar的height小于最大值,那么当前的bar能贡献的water就是height - curMaxHeight。否则的话,更新curMaxHeight。

    为了更好理解这个算法,我们来track下这个过程:

         

             

    最后遍历右半边。过程是一模一样的,只不过i从最右边靠近Mid。

    解法二

    代码如下:

     1 public static int trap2(int[] A){
     2         if(A.length <= 1) return 0;
     3         int curMaxHeight = 0;
     4         int water = 0;
     5         int mid = 0;
     6         for(int i = 0; i < A.length;i++){
     7             if(A[i] > A[mid]) mid = i;
     8         }
     9         
    10         for(int i = 0; i < mid; i++){
    11             if(A[i] < curMaxHeight){
    12                 water += curMaxHeight - A[i];
    13             }else curMaxHeight = A[i];
    14         }
    15         
    16         curMaxHeight = 0;
    17         for(int i = A.length - 1; i > mid; i--){
    18             if(A[i] < curMaxHeight){
    19                 water += curMaxHeight -A[i];
    20             }else curMaxHeight = A[i];
    21         }
    22         return water;
    23     }
    View Code

    其实,本质上来说,第一步保障了左右两边的水总是能“放进去”,因为大板子在中间档着嘛。

    Faint,我写到这里,想到这个代码其实也是蛮简单的,为啥我就没想到呢!唉。。。

    总结下:

    复杂的代码是错误的代码。没有例外。

  • 相关阅读:
    我从0开始开发了一个LDAP服务。
    C#开发中常用的小功能
    webapi swagger 报错 路由集合中已存在名为“swagger_docsswagger/docs/{apiVersion}”的路由。路由名称必须唯一
    h5 web vlc 播放rtsp流
    Docker的基础概念与在window10下的安装
    .Net Core JWT 动态设置接口与权限
    .Net Core官方的 JWT 授权验证
    IdentityServer4中文文档
    中介者模式及在NetCore中的使用MediatR来实现
    .Net Core 使用 FluentValidation
  • 原文地址:https://www.cnblogs.com/lichen782/p/Leetcode_Trapping_Rain_Water.html
Copyright © 2011-2022 走看看