题解 | #数组中相加和为0的三元组#

容器盛水问题

http://www.nowcoder.com/practice/31c1aed01b394f0b8b7734de0324e00f

C++版本3种方法循序渐进

// NC128容器盛水问题
class Solution {
public:
    /**
     * max water
     * @param arr int整型vector the array
     * @return long长整型
     */
    long long maxWater(vector<int>& arr) {

    /*     法1------------【超时】---------------------
        每个位置能盛的水由左右的最大值中最小值决定(木桶原理)
        该方法是累加每个位置的水量
        时间复杂度:O(N^2),遍历每个位置O(n),针对每个位置求左右侧的最值O(n),空间O(1)
    */    

        int  len=arr.size();
        if(len<3) return 0;

        long long ret=0;
        //遍历每个位置,第一和最后一个位置不用遍历
        for(int i=1;i<len-1;++i){
            int leftmax=0;
            int rightmax=0;
            //找到i左侧的最大值
            for(int left=0;left<i;++left){
                leftmax=max(leftmax,arr[left]);
            }
            //找到i右侧的最大值
            for(int right=i+1;right<len;++right){
                rightmax=max(rightmax,arr[right]);
            }
            //累加
            ret += max( min(leftmax,rightmax)-arr[i] , 0 );
        }
     return ret;


     // 法2-----------------------------------------------
     // 每次遍历比较麻烦,遍历一次,用2个数组保存每个位置左右侧的最值,再累加
        int  len = arr.size();
        if(len<3) return 0;

        long long ret = 0;
        int leftmax[len];
        int rightmax[len];
        leftmax[0]=0;
        rightmax[len-1]=0;
        //leftmax[i]表示arr[0...i-1]的最大值,如果本身最大,那最大值就是自身
        for(int i=1; i<len; ++i){
            leftmax[i] = max( leftmax[i-1] , arr[i-1] );
        }
        //rightmax[i]表示arr[i+1...len-1]的最大值,如果本身最大,那最大值就是自身
        for(int i=len-2;i>=0;--i){
            rightmax[i] = max( rightmax[i+1] , arr[i+1] );
        }
        //累加,对于任意一个位置,左侧的最大值为leftmax[i],右侧为rightmax[i];
        for(int i=1;i<len-1;++i){
            ret+= max( min( leftmax[i],rightmax[i] ) - arr[i] , 0    );
        }
        return ret;
    /*         
        法3--------------------------------
        左右指针 左右指针分别从第2和倒数第2位置开始
        leftmax:arr[0...i-1]的最大值
        rightmax表示arr[i+1...len-1]之间的最大值

        如果leftmax<=rightmax 那么可以求出【i】位置的是max(leftmax -arr[i],0);
        因为:右指针从右往左走,i和右指针中间的位置虽然没有遍历,但是这些位置的rightmax一定>=当前rightmax,所以可以求

        如果leftmax>rightmax,那么可以求出【len-2】位置的是max(right-arr[i],0);

        当左右指针相遇【之后】,就退出
        会不会只求了一半?
            不会,当leftmax<=rightmax 时候,可以确定左指针位置可以求,因为左指针右边未遍历区域的max不会小于当前rightmax
            右指针位置的水量在leftmax>rightmaxd的时候,可以求,水量算多少取决于短板rihgmax大小
            因为当leftmax>rightmax后,后续的leftmax不会小于当前的leftmax.
     */    
        int  len = arr.size();
        if(len<3) return 0;

        long long ret = 0;
        int left=1;//左指针
        int right=len-2;
        int leftmax=arr[0];//位置【i】左侧的最大值
        int rightmax=arr[len-1];
        while(left<=right){
            if(leftmax<=rightmax){
                ret += max( leftmax-arr[left] , 0 ); 
                leftmax=max(leftmax,arr[left++]);//更新leftmax,为下一个位置做准备
            }else{
                ret += max( rightmax - arr[right] , 0 );
                rightmax = max( rightmax, arr[right--] );
            }

        }
        return ret;

    }
};
全部评论

相关推荐

爱看电影的杨桃allin春招:我感觉你在炫耀
点赞 评论 收藏
分享
1 收藏 评论
分享
牛客网
牛客企业服务