1. 程式人生 > >Leetcode個人題解11

Leetcode個人題解11

LEETCODE專題

11. Container With Most Water

題目要求:
這裡寫圖片描述

這裡要求我們將陣列中的每個元素(下標為i,從1開始)看成一條向量,起點為(i, 0), 終點為(i, a[i]),這樣每條向量的長度就是a[i]。然後再找出這些向量中的兩條,使它們和x軸形成的容器面積最大。當然不允許傾斜向量。

問題:

  1. 如何計算容器的面積?
  2. 如何減少時間複雜度?

思路:

  1. 計算容器的面積,我們需要明白“木桶效應”——在所有組成木桶的木材中,最短的那根對木桶裝的水量起著決定性作用。這裡也是一樣,我們計算容器的面積,其實也就是計算一個長方形的面積。假設i、j分別是這兩條向量的下標且i是a[i] < a[j],那麼寬就是兩條向量在x軸上的投影點的距離,也就是下標的差;長則是兩條向量中最短的那條向量的終點的y值,也就是a[i]。
  2. 這裡筆者曾經使用過兩重迴圈。後來發現這種解法十分的naive,時間複雜度為O(n^2)的演算法分分鐘超時。於是改進了一下思路,發現,其實這和快速排序演算法十分的相似,即剛開始選定第一條向量和最後一條向量,然後讓長度較短的一條向量的下標往另一個下標靠攏,若移動的過程中得到的新的向量的長度比之前的短,繼續移動,直到得到的向量的長度更長為止,此時記錄新的容器面積,得到的倘若比最大面積大的話就覆蓋最大面積。這裡之所以可以拋棄長度更短的向量,是因為下標在移動的過程中本身寬就在減少,由上面的討論可知,此時長由該向量長度決定,若得到的長度更短,容器面積自然也更小,也就沒有記錄新的容器面積的必要了。

下面直接上程式碼:

class Solution {
public:
    int maxArea(vector<int>& height) {
        /*
         * 1 loop.
         * Firstly initial the maxArea to be
         * the area of the container formed
         * by the first line and the last
         * line. Then let index of the shorter
         * line goes closer to
the longer one. * * Record the area each time it finds * a larger one. * */ int width, length, index; int maxArea = -1; int left = 0, right = height.size() - 1; do { width = right - left; if (height[left] < height[right]) { length = height[left]; index = left; while (left < right && height[left] <= length) left++; } else { length = height[right]; index = right; while (left < right && height[right] <= length) right--; } maxArea = maxArea > width * length ? maxArea : width * length; } while (left < right); return maxArea; } };

時間複雜度:O(n)