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;
    }






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章