Processing math: 100%

【題解】LeetCode - 53. Maximum Subarray

題目連結

題目大意

給定一個長度為 n 的數列 a0,,an1,求最大連續和。
  • 1n105
  • |ai|104

題解

最大連續和有兩種經典的作法,DP 和分治。

DP

定義 dp[i] 為考慮 a0,,ai 且包含 ai 的最大連續和。不難發現如果 dp[i1]<0,則單獨取 ai 會更好,因此我們得到 dp[i]=max(dp[i1],0)+ai。因為 dp[i] 都只跟 dp[i1] 有關,因此我們只需要用一個變數去紀錄前一項的 dp 值就好了。時間複雜度為 O(n)
class Solution {
public:
    int maxSubArray(vector<int>& a) {
        int ans = INT_MIN;
        int dp = 0;
        for(auto x : a) {
            dp = max(dp, 0) + x;
            ans = max(ans, dp);
        }
        return ans;
    }
};

分治

定義 solve(l,r)al,,ar1 的最大連續和,最後所求就是 solve(0,n)。假設我們現在要求 [l,r) 的最大連續和,令 m=l+r2[l,r) 的最大連續如果完全落在 m 的左邊,則在呼叫 solve(l,m) 時就會被找到。相同的,如果完全落在右半邊,則呼叫 solve(m,r) 時會被找到。最後一個情況是最大連續和橫跨 m,那麼就會是 [l,m) 的最大後綴和 + [m,r) 的最大前綴和。這兩個東西都能夠在 O(rl) 求出。綜合上述的做法,我們得到 T(n)=2T(n2)+O(n),根據主定理我們得到 T(n)=O(nlogn)

我們其實還能夠做的更好。最大前綴和和最大後綴和在函數回傳的時候可以一併維護,這樣我們就不用額外花費 O(rl) 的時間去計算。複雜度為 T(n)=2T(n2)+O(1)T(n)=O(n)

分治 O(nlogn) 作法
class Solution {
public:
    int maxSubArray(vector<int>& a) {
        return solve(a, 0, a.size());
    }
    
    int solve(const vector<int>& a, int l, int r) {
        if(l + 1 == r) {
            return a[l];
        }
        int m = (l + r) / 2;
        int ans = max(solve(a, l, m), solve(a, m, r));
        int pref = 0, max_pref = INT_MIN;
        for(int i = m - 1; i >= l; i--) {
            pref += a[i];
            max_pref = max(max_pref, pref);
        }
        int suff = 0, max_suff = INT_MIN;
        for(int i = m; i < r; i++) {
            suff += a[i];
            max_suff = max(max_suff, suff);
        }
        ans = max(ans, max_pref + max_suff);
        return ans;
    }
};
分治 O(n) 作法
class Solution {
public:
    int maxSubArray(vector<int>& a) {
        auto [ans, max_pref, max_suff, sum] = solve(a, 0, a.size());
        return ans;
    }

    tuple<int, int, int, int> solve(const vector<int>& a, int l, int r) {
        if(l + 1 == r) {
            return {a[l], a[l], a[l], a[l]};
        }
        int m = (l + r) / 2;
        auto [ans_l, max_pref_l, max_suff_l, sum_l] = solve(a, l, m);
        auto [ans_r, max_pref_r, max_suff_r, sum_r] = solve(a, m, r);
        int ans = max(ans_l, ans_r);
        ans = max(ans, max_suff_l + max_pref_r);
        int max_pref = max(max_pref_l, sum_l + max_pref_r);
        int max_suff = max(max_suff_r, sum_r + max_suff_l);
        int sum = sum_l + sum_r;
        return {ans, max_pref, max_suff, sum};
    }
};

如果本文對您有幫助的話幫忙點擊廣告和分享吧!

© 若無特別註明,本站文章皆由 WeakMouse's Coding Blog 原創 ,轉載引用本文前請先留言告知。本文轉載請註明文章源自 WeakMouse's Coding Blog ,作者 ,並附上原文連結: 【題解】LeetCode - 53. Maximum Subarray

張貼留言

0 留言