1. 程式人生 > 其它 >LeetCode 11-20題

LeetCode 11-20題

本部落格記錄的是 LeetCode 11 到 20 題的題解

11. Container With Most Water

解決該問題,主要有兩種思路,

  1. 雙指標演算法
  2. 滑動區間內 + 雙指標

雙指標演算法

雙指標演算法特別簡單,具體操作如下:
我們使用指標 i, j分別指向 height 陣列的首尾兩端,並計算 i, j 所構成容器的面積
然後選擇高度小的指標指向內部,不斷獲得容器面積,更新 Res 答案。

演算法正確性的證明:
我們假設 res_i, res_j 是我們最終產生最大容器的兩個高度,我們使用雙指標演算法時候,一定會有一個指標率先指向 res_i或者是res_j,在這裡,我們假設是 i

率先指向了res_i
我們此時我們對 height[res_i] 和 height[res_j] 的情況進行討論,看 i, j是否可以同時指向 res_i, res_j
第一種情況,height[res_i] < height[res_j]

指標 i不會一定,j不斷左移必定會指向res_j,主要是 height[j] 必須小於 height[res_i],否則 res_i 與 res_j便不會是最終解,與前提矛盾。

第二種情況,height[res_i] > height[res_j]

指標 i不會一定,j不斷左移必定會指向res_j,主要是 height[j] 必須小於 height[res_j],否則 res_i 與 res_j便不會是最終解,與前提矛盾。
那麼也一定小於height[res_i]

總而言之,當指標i指向了 res_i, res_j之外的高度,一定要小於 height[res_i], height[res_j]的最小值,那麼也就一定小於 height[res_i],也就會指標j最終指向res_j

c++ 程式碼

class Solution {
public:
    int maxArea(vector<int>& height) {
        int i = 0, j = height.size() - 1;
        int res = 0;
        while (i < j) {
            res = max(res, min(height[i], height[j]) * (j - i));
            if (height[i] < height[j]) {
                i += 1;
            } else {
                j -= 1;
            }
        }
        return res;
    }
};

python 程式碼

class Solution:
    def maxArea(self, height: List[int]) -> int:
        i, j = 0, len(height) - 1
        res = 0
        while i < j:
            res = max(res, min(height[i], height[j]) * (j - i))
            if height[i] < height[j]:
                i += 1
            else:
                j -= 1
        return res

折半查詢做法

c++程式碼和註解:

/*
    我們把 i 當做右邊界,而且是較小的右邊界,那麼我們只需要找到左側大於等於 height[i] 的靠左的部分即可
    主要是根據貪心的原則 如果 height[j] >= height[j + 1] 那麼 j + 1根本就沒有什麼用處了,因為 j 這個位置比他高,還比他寬
*/
typedef pair<int, int> PII;
class Solution {
public:
    int getMax(vector<int> v) {
        vector<PII> a;
        a.push_back(PII(v[0], 0));
        int l, r, mid;
        int res = 0;
        for (int i = 1; i < v.size(); i ++ ) {
            if (a.back().first < v[i]) {
                a.push_back(PII(v[i], i));
            } else {
                // 在 a 遞增陣列中尋找大於等於 v[i] 的最小值
                l = 0, r = a.size() - 1;
                while (l < r) {
                    mid = l + r >> 1;
                    if (a[mid].first >= v[i]) {
                        r = mid;
                    } else {
                        l = mid + 1;
                    }
                }
                res = max(res, v[i] * (i - a[l].second));
            }
        }
        return res;
    }

    int maxArea(vector<int>& height) {
        return max(getMax(height), getMax(vector<int> (height.rbegin(), height.rend())));
    }
};

python 程式碼和註解

class Solution:
    def getMax(self, h):
        res = 0
        a = []
        for i, x in enumerate(h):
            if i == 0 or a[-1][0] < x:
                a.append([x, i])
            else:
                l, r = 0, len(a)
                while l < r:
                    mid = (l + r) // 2
                    if a[mid][0] >= x:
                        r = mid
                    else:
                        l = mid + 1
                res = max(res, x * (i - a[l][1])) 
        return res

    def maxArea(self, height: List[int]) -> int:
        return max(self.getMax(height), self.getMax(height[::-1]))