📘 題目敘述
給你一個整數陣列 nums,請找出具有最大總和的連續子陣列(至少包含一個元素),並回傳這個最大總和。
條件限制
1 <= nums.length <= 10^5-10^4 <= nums[i] <= 10^4
🧠 解題思路(一)前綴和
我的想法是用前綴和把「任意一段子陣列的總和」快速算出來。
我先建立一個前綴和陣列 sum,讓:
sum[0] = 0sum[t] = nums[0] + nums[1] + ... + nums[t-1]
這樣一來,任何連續子陣列 nums[j ... k-1] 的總和就可以用:
sum[k] - sum[j]
所以我就把所有可能的 (j, k) 都枚舉一次,找最大的 sum[k] - sum[j],更新到 ans。
這份寫法的重點是:
前綴和讓子陣列總和的計算變成 O(1),但我仍然用雙迴圈枚舉所有區間,所以總時間會是 O(n^2)。
所有變數
nums:題目輸入陣列sum:前綴和陣列,sum[t]代表前t個元素的總和ans:目前找到的最大子陣列總和
🪜 主要流程步驟(一)
1. 建立前綴和陣列 sum
- 先放一個
0當作起點,表示「前 0 個元素總和」 - 依序把
nums[i]加到sum.back(),得到新的前綴和並 push 進sum - 建完後
sum長度會是nums.size() + 1
2. 枚舉所有子陣列,用 sum[k] - sum[j] 算總和
j從0走到sum.size() - 2k從j + 1走到sum.size() - 1- 這樣
(j, k)就代表一段非空子陣列 - 用
sum[k] - sum[j]得到該段子陣列總和,並用它更新ans
3. 回傳答案
- 雙迴圈跑完後,
ans就是最大連續子陣列總和
💻 程式碼實作(一)
class Solution {
public:
int maxSubArray(vector<int>& nums) {
if (nums.size() == 1) {
return nums[0];
}
vector<int> sum = {0};
int ans = INT_MIN;
for (int i = 0; i < nums.size(); i++) {
sum.push_back(nums[i] + sum.back());
}
for (int j = 0; j < sum.size() - 1; j++) {
for (int k = j + 1; k < sum.size(); k++) {
ans = max(ans, sum[k] - sum[j]);
}
}
return ans;
}
};
🧠 解題思路(二)DP
這題我用的是很直觀的 DP 思考:
我走到某個位置時,我要嘛把它接在前面的子陣列後面,要嘛從這裡重新開一段。
哪一個比較好?看「前面的累積和是不是負的」。
我用 now 表示「目前這段連續子陣列的總和」,也就是我正在維護的一段候選解。
當我遇到下一個數字 i:
- 如果
now < 0,代表我目前這段的總和是負的
那把它接下去只會拖累未來的總和,所以我乾脆放棄它,改成從i重新開始一段:now = i - 如果
now >= 0,代表目前這段總和是正的(或至少不負)
那接上i只會讓總和更大,所以直接累加:now += i
接著我用 best 來記錄「目前為止看過的最大子陣列總和」,每走一步就更新一次 best = max(best, now)。
這樣一次掃描就能得到答案。
所有變數
now:目前正在累積的連續子陣列總和(以「結尾在當前元素」的角度來看)best:目前為止的最大子陣列總和(最後回傳它)
🪜 主要流程步驟(二)
1. 初始化 now 與 best
now初始化成很小(INT_MIN),表示還沒開始累積best也初始化成很小,表示答案還沒被更新過
2. 從左到右掃描每個元素,決定要不要重開一段
每遇到一個元素 i:
- 如果
now < 0
代表前面那段是負貢獻,直接丟掉,從i開始:now = i - 否則
代表前面那段不會拖累,接著加:now += i
3. 每一步都更新 best
best = max(best, now)- 代表我把「到目前為止所有可能連續子陣列的最大值」都記下來
4. 回傳 best
掃描完後 best 就是最大連續子陣列總和。
💻 程式碼實作(二)
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int now = INT_MIN, best = INT_MIN;
for (int i : nums) {
if (now < 0) {
now = i;
} else {
now += i;
}
best = max(best, now);
}
return best;
}
};
🔗 題目連結
https://leetcode.com/problems/maximum-subarray/