zoukankan      html  css  js  c++  java
  • leetcode 第41题 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!

    题目意思应该很好理解,就是给定数组后,如图,能存放多少单位的水。网上大多数人的方法都是累加每柱能容纳的水。例如。我的做法是,累加当前到之后第一个不小于自己的柱子能存的水。定义一个start,每次计算完一块水域之后,start跳到这块水域的右边柱子往后找新的水域。直到最后。应该是O(n)的。现在就出现问题了,如果出现4 2 3 的例子,如果按照刚才的思路,4的时候,后面没有大于等于4的数,那start就++的话,答案最终是零了。解决的办法是,如果之后没有发现比大于等于自己的柱子,那么就将自己减一,再判断,知道自己为零,或者是找到不小于自己的柱子为止。

    oj上证明我的方法比别人快5倍。

    class Solution {
    public:
        int trap(int A[], int n) 
        {
            int sum = 0, start = -1;
            while(++start < n && A[start] == 0);// 找到第一个非零为start
            while(start < n)
            {
                int next = start, minus = 0;
                while(++next < n && A[next] < A[start])
                {
                    minus += A[next];
                }
                if (next == n) // 说明之后没有比当前大或者相等的数,所以要将A[start]值减一后再判断,直到有找到不小于当前的数或者已经减到0了
                {
                    A[start] -= 1;
                    if (A[start] > 0)//只要大于零就要再判断之后有没有不小于当前的数
                        continue;
                }
                sum += (next - start - 1) * A[start] - minus;
                start = next;
            }
            return sum;
        }
    };

    发现oj上如果把注释去掉,居然更快。。。

    2015/04/03: 只扫描一遍,left从左往右,right从右往左,每次比较小的往里走,走到比自己大的位置,过程当中记录可以盛的水。(阿里2015校招实习生笔试题)

    class Solution {
    public:
        int trap(int A[], int n) {
            int left = 0, right = n - 1, water = 0;
            while(left < right){
                if (A[left] < A[right]){
                    int i = left + 1;
                    while(i < right && A[i] < A[left]){
                        water += A[left] - A[i++];
                    }
                    left = i;
                }
                else{
                    int i = right - 1;
                    while(i > left && A[i] < A[right]){
                        water += A[right] - A[i--];
                    }
                    right = i;
                }
            }
            return water;
        }
    };

    扫描两遍:第一遍从左往右,记录当前左边的最大, 第一遍从右往左,记录到当前的最大,根据左边和右边以及自己的数,就可以判断当前是否可以盛水。

    class Solution {
    public:
        int trap(int A[], int n) {
            if (n <= 2) return 0;
            int water = 0, perm[n], tmpMax = 0;
            for (int i = 1; i < n; ++i){
                if (tmpMax < A[i-1]){
                    tmpMax = A[i-1];
                }
                perm[i] = tmpMax;
            }
            tmpMax = 0;
            for (int i = n - 2; i > 0; --i){
                if (tmpMax < A[i+1]){
                    tmpMax = A[i+1];
                }
                water += min(perm[i], tmpMax) - A[i] > 0 ? min(perm[i], tmpMax) - A[i] : 0;
            }
            return water;
        }
    };
  • 相关阅读:
    面试题58 二叉树的下一个结点
    面试题57 删除链表中重复的结点
    面试题56 链表中环的入口结点
    面试题55 字符流中第一个不重复的字符
    面试题54 表示数值的字符串
    面试题50 树中两个结点的最低公共祖先
    面试题53 正则表达式匹配
    面试题52 构建乘积数组
    面试题51 数组中重复的数字
    Qt链接库出错version Qt_5 not defined
  • 原文地址:https://www.cnblogs.com/higerzhang/p/4053272.html
Copyright © 2011-2022 走看看