如何裝最多的水? — leetcode 11. Container With Most Water


炎炎夏日,還是呆在空調房里切切題吧。

Container With Most Water,題意其實有點噱頭,簡化下就是,給一個數組,恩,就叫 height 吧,從中任選兩項 i 和 j(i <= j),使得 Math.min(height[i], height[j]) * (j - i) 最大化,求解這個最大值。

O(n^2)

O(n^2) 復雜度的解法非常容易想到,直接兩兩枚舉。

var maxArea = function(height) {
  var len = height.length;
  var maxn = 0;

  for (var i = 0; i < len; i++)
    for (var j = i + 1; j < len; j++)
      maxn = Math.max(maxn, Math.min(height[i], height[j]) * (j - i));

  return maxn;
};

提交,TLE,看了下數據,數組長度 1w,復雜度直接飆到億級,不 TLE 才怪了。

O(nlogn)

我們假設數組為 [a1, a2, ..., an],我們實際需要求得的其實是一個子數組。假設這個子數組的最后一個元素是 a5,同時我們規定該子數組最后一個元素不大於第一個元素,那么實際我們需要求的是 a1, a2, a3, a4 中哪個元素比 a5 大(或者相同),並且這個元素越前面越好。

這樣,我們可以遍歷每個元素,將這個元素確定為子數組的最后一個元素,同時去求前面已經被遍歷過的元素中,大於等於該元素並且最左的元素。對於求這個最左元素,我們可以維護一個單調遞增的數組,用二分去解。

二分需要求解一個遞增序列中,剛好大於等於指定元素的位置,這個 case 沒有出現在 二分查找大集合(媽媽再也不用擔心我的二分查找了),我們可以稍微變個形。

// 求解 a 數組中剛好大於等於 target 的位置
// 如果都小於 target 則返回 a.length
function binarySearch(a, target) {
  target += 1;
  var start = 0
    , end = a.length - 1;

  while(start <= end) {
    var mid = ~~((start + end) >> 1);
    if (a[mid] >= target)
      end = mid - 1;
    else
      start = mid + 1;
  }

  if (a[start - 1] === target - 1)
    start -= 1;
  return start;
}

還需要注意的一點是,必須正反來兩次,因為我們假設子數組的最后一個元素小於等於首元素,還需要考慮另一種情況,即子數組首元素小於等於最后一個元素。

其他部分問題不大,具體代碼可以參考 https://github.com/hanzichi/leetcode/blob/master/Algorithms/Container With Most Water/O(nlogn).js

提交,AC,擊敗 4% ... 勢必還有更優的解法,而且根據我的經驗,如果這是標程正解的話,這道題的難度應該是 Hard 而不是 Medium 了。

O(n)

正解的復雜度應該是 O(n) 的。

我們可以舉個簡單的例子,假設數組是 [2, 3, 4, 5, 4, 3],那么最長的子數組一定只有一個,即取全部元素,這樣能裝的水的數量是 2 * 5 。接下去我們的子元素,長度一定是會變小的,有兩種情況,為 [2, 3, 4, 5, 4][3, 4, 5, 4, 3]。我們來看 [2, 3, 4, 5, 4],這種情況下,顯然比取全部元素求得的結果 10 要小,為什么這么說?因為兩者的基准都是按 2 來算的,但是取全部元素長度大。

似乎有點眉目了,再來看 [2, 3, 4, 5, 4, 3] 這個原始的數組,從中找出一個子數組,如果以 2 為子數組最左的元素,那么這個子數組求解的值(即裝水的量),不可能比 [2, 3, 4, 5, 4, 3] 這個原始數組求到的 10 要大了,有木有?!因為該子數組裝水的基准,是不可能比 2 大了的。

這樣,我們似乎可以用一點點貪心去解這道題,一步步縮小子數組的大小。

while (start <= end) {
  maxn = Math.max(maxn, Math.min(height[end], height[start]) * (end - start));

  if (height[end] < height[start])
    end --;
  else
    start ++;
}

完整代碼可以參考 https://github.com/hanzichi/leetcode/blob/master/Algorithms/Container With Most Water/O(n).js


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM