題目大意
給定一個長度為 n 的數列 a0,…,an−1,求最大連續和。
- 1≤n≤105
- |ai|≤104
題解
最大連續和有兩種經典的作法,DP 和分治。
DP
定義 dp[i] 為考慮 a0,…,ai 且包含 ai 的最大連續和。不難發現如果 dp[i−1]<0,則單獨取 ai 會更好,因此我們得到 dp[i]=max(dp[i−1],0)+ai。因為 dp[i] 都只跟 dp[i−1] 有關,因此我們只需要用一個變數去紀錄前一項的 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,…,ar−1 的最大連續和,最後所求就是 solve(0,n)。假設我們現在要求 [l,r) 的最大連續和,令 m=⌊l+r2⌋,[l,r) 的最大連續如果完全落在 m 的左邊,則在呼叫 solve(l,m) 時就會被找到。相同的,如果完全落在右半邊,則呼叫 solve(m,r) 時會被找到。最後一個情況是最大連續和橫跨 m,那麼就會是 [l,m) 的最大後綴和 + [m,r) 的最大前綴和。這兩個東西都能夠在 O(r−l) 求出。綜合上述的做法,我們得到 T(n)=2T(n2)+O(n),根據主定理我們得到 T(n)=O(nlogn)。
我們其實還能夠做的更好。最大前綴和和最大後綴和在函數回傳的時候可以一併維護,這樣我們就不用額外花費 O(r−l) 的時間去計算。複雜度為 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 留言