leetcode 计算最大盛水量

题目出处

给字n个非负整数, a1,a2, … , an,  对应着坐标轴(i, ai),  对每个数连接x轴画一条线段,端点 (i, ai)  和 (i, 0).
对两个数,连接端点, 再与x轴形成长方形, 求长方形的面积就想关于盛水的体积, 求最大的盛水量。

如假设给定的10个数:  [5, 4, 3, 10, 2, 7, 8, 6, 1, 9],即10 个点 (0, 5), (1, 4), (2, 3), (3, 10), … ,(9, 9)  对应的直观图如下




蓝色区域代码的是 (0, 5),(3, 10)两点的盛水量为: 5*3 = 15.
相应的, 灰色区域代码的是 (3 10),(5, 7)两点的盛水量为: 7*(5 -3) = 14.
相应的, 黄色区域代码的是 (6, 8),(9, 9)两点的盛水量为: 8*(9 -6) = 24.
上图数据中,最大值为(3, 10) , (9, 9), 盛水量为: 9 * (9-3) = 54 

分析
最直接的求法是计算两两计算一遍,求最大值。
但是明显的,有很多没必要的运算. 比如上图中的(1, 4), (2, 3) 与(10, 10) 的计算。

由于这是计算盛水量,所以主要取决于较小的数据,所以最大的数据再大,也没有起作用。
考虑到一般情况:
两个数字(i, ai), (j, aj), 他们的盛水量为 area =(j-i)*min(ai, aj),  取(k, ak) 使 i < k < j, 使面积比area更大。
不失一般性,设 ai <= aj,则min(ai, aj) = ai.
当ak <= ai 时, 由于  (k-i) * ak < area 和 (j-k) * ak < area(由于 k-i < j-i 和 j-k < j-i), 所以这种情况得到的结果肯定小于 area. 可以不考虑。

当 ak > ai 时
     ak 与ai的盛水量: (k-i)*ai < area, 所以这种情况也不需要考虑。
     ak与aj的盛水量: (j-k)*min(ak, aj) 由于 j-k < j-i 而 min(ak, aj) > ai, 不确定是否大于area. 
所以可得到简单算法:
  1. 取第一和最后的值为初始值,计算最近 盛水量。
  2. 往中间移动较小值的指针,录找比它大的数。
  3. 再计算盛水量,并比较大小。
  4. 重复2, 3.
算法代码

int maxArea(vector<int>& height) {
         
         int first = 0, end = height.size()-1;
         int min = height[first] > height[end] ?  end :  first;
         int maxArea = (end-first)*height[min];
          
         while(first < end){
            //  cout<<first << " " << end << " min:" << min << endl;
            // 移动最小值到下一个比当前最小值大的数。
             if(first == min){
                while(first < end && height[first] <= height[min]) first += 1;
             }
             if(end == min){
                while(first < end && height[end] <= height[min]) end -= 1;
             }
            //  没有就退出
            if(first >= end ) break;
            // 计算盛水量比较
            min = height[first] < height[end] ? first : end;
            int area = (end-first) * height[min];
             if(area > maxArea)  
                 maxArea = area; 
              
         } 
          return maxArea;
    }






  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值