1. 程式人生 > 其它 >【刷穿 LeetCode】11. 盛最多水的容器(中等)

【刷穿 LeetCode】11. 盛最多水的容器(中等)

技術標籤:刷穿 LeetCode演算法資料結構leetcode面試貪心演算法

題目描述

給你 n 個非負整數 a1,a2,...,an,每個數代表座標中的一個點 (i, ai) 。在座標內畫 n 條垂直線,垂直線 i 的兩個端點分別為 (i, ai)(i, 0) 。找出其中的兩條線,使得它們與 x 軸共同構成的容器可以容納最多的水。

說明:你不能傾斜容器。

示例 1:

輸入:[1,8,6,2,5,4,8,3,7]
輸出:49 
解釋:圖中垂直線代表輸入陣列 [1,8,6,2,5,4,8,3,7]。
在此情況下,容器能夠容納水(表示為藍色部分)的最大值為 49。

示例 2:

輸入:height = [1,1]
輸出:1

示例 3:

輸入:height = [4,3,2,1,4]
輸出:16

示例 4:

輸入:height = [1,2,1]
輸出:2

提示:

  • n = height.length
  • 2 <= n <= 3 * 104
  • 0 <= height[i] <= 3 * 104

樸素解法

我們可以直接列舉所有的情況:先列舉確定左邊界,再往右列舉確定右邊界。

然後再記錄列舉過程中的最大面積即可:

class Solution {
    public int maxArea(int[] height) {
        int n = height.length;
        int
ans = 0; for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { int w = j - i; int h = Math.min(height[i], height[j]); ans = Math.max(w * h, ans); } } return ans; } }

時間複雜度: O ( n 2 ) O(n ^ 2)

O(n2)

空間複雜度: O ( 1 ) O(1) O(1)


雙指標+貪心解法

先用兩個指標 ij 指向左右邊界,然後考慮指標應該怎麼移動。

由於構成矩形的面積,取決於 ij 之間的距離(記為 w) 和 ij 下標對應的高度的最小值(記為 h)。

首先無論是 i 指標往右移動還是 j 指標往左移動都會導致 w 變小,所以想要能夠列舉到更大的面積,我們應該讓 h 在指標移動後變大。

不妨假設當前情況是 height[i] < heigth[j](此時矩形的高度為 height[i]),然後分情況討論:

  • ij 兩者高度小的指標移動,即 i 往右移動:

    • 移動後,i 指標對應的高度變小,即 height[i] > height[i + 1]wh 都變小了,面積一定變小
    • 移動後,i 指標對應的高度不變,即 height[i] = height[i + 1]w 變小,h 不變,面積一定變小
    • 移動後,i 指標對應的高度變大,即 height[i] < height[i + 1]w 變小,h 變大,面積可能會變大
  • ij 兩者高度大的指標移動,即 j 往左移動:

    • 移動後,j 指標對應的高度變小,即 height[j] > height[j - 1]w 變小,h 可能不變或者變小(當 height[j - 1] >= height[i] 時,h 不變;當 height[j - 1] < height[i] 時,h 變小),面積一定變小
    • 移動後,j 指標對應的高度不變,即 height[j] = height[j - 1]w 變小,h 不變,面積一定變小
    • 移動後,j 指標對應的高度變大,即 height[j] < height[j - 1]w 變小,h 不變,面積一定變小

綜上所述,我們只有將高度小的指標往內移動,才會列舉到更大的面積:

class Solution {
    public int maxArea(int[] height) {
        int n = height.length;
        int i = 0, j = n - 1;
        int ans = 0;
        while (i < j) {
            ans = Math.max(ans, (j - i) * Math.min(height[i], height[j]));
            if (height[i] < height[j]) {
                i++;
            } else {
                j--;
            }
        }
        return ans;
    }
}

時間複雜度:會對整個陣列掃描一遍。複雜度為 O ( n ) O(n) O(n)

空間複雜度: O ( 1 ) O(1) O(1)


最後

這是我們「刷穿 LeetCode」系列文章的第 No.11 篇,系列開始於 2021/01/01,截止於起始日 LeetCode 上共有 1916 道題目,部分是有鎖題,我們將先將所有不帶鎖的題目刷完。

在這個系列文章裡面,除了講解解題思路以外,還會盡可能給出最為簡潔的程式碼。如果涉及通解還會相應的程式碼模板。

由於 LeetCode 的題目隨著周賽 & 雙週賽不斷增加,為了方便我們統計進度,我們將按照系列起始時的總題數作為分母,完成的題目作為分子,進行進度計算。當前進度為 11/1916

為了方便各位同學能夠電腦上進行除錯和提交程式碼,我建立了相關的倉庫:Github 地址 & Gitee 地址

在倉庫地址裡,你可以看到系列文章的題解連結、系列文章的相應程式碼、LeetCode 原題連結和一些其他的優選題解。

#演算法與資料結構

#LeetCode題解

#演算法面試

宮水三葉的刷題日記