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

炎炎夏日,仍是呆在空調房裏切切題吧。javascript

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

O(n^2)

O(n^2) 複雜度的解法很是容易想到,直接兩兩枚舉。java

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 纔怪了。git

O(nlogn)

咱們假設數組爲 [a1, a2, ..., an],咱們實際須要求得的實際上是一個子數組。假設這個子數組的最後一個元素是 a5,同時咱們規定該子數組最後一個元素不大於第一個元素,那麼實際咱們須要求的是 a1, a2, a3, a4 中哪一個元素比 a5 大(或者相同),而且這個元素越前面越好。github

這樣,咱們能夠遍歷每一個元素,將這個元素肯定爲子數組的最後一個元素,同時去求前面已經被遍歷過的元素中,大於等於該元素而且最左的元素。對於求這個最左元素,咱們能夠維護一個單調遞增的數組,用二分去解。數組

二分須要求解一個遞增序列中,恰好大於等於指定元素的位置,這個 case 沒有出如今 二分查找大集合(媽媽不再用擔憂個人二分查找了),咱們能夠稍微變個形。code

// 求解 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;
}

還須要注意的一點是,必須正反來兩次,由於咱們假設子數組的最後一個元素小於等於首元素,還須要考慮另外一種狀況,即子數組首元素小於等於最後一個元素。htm

其餘部分問題不大,具體代碼能夠參考 https://github.com/hanzichi/leetcode/blob/master/Algorithms/Container%20With%20Most%20Water/O(nlogn).jsblog

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

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%20With%20Most%20Water/O(n).js

相關文章
相關標籤/搜索