# 53. Maximum Subarray **練習日期:** 2026-02-10 **難度:** Medium **類型:** Array、Prefix Sum ## 📘 題目敘述 給你一個整數陣列 `nums`,請找出具有最大總和的**連續子陣列**(至少包含一個元素),並回傳這個最大總和。 ### 條件限制 * `1 <= nums.length <= 10^5` * `-10^4 <= nums[i] <= 10^4` ## 🧠 解題思路(一)前綴和 我的想法是用**前綴和**把「任意一段子陣列的總和」快速算出來。 我先建立一個前綴和陣列 `sum`,讓: * `sum[0] = 0` * `sum[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() - 2` * `k` 從 `j + 1` 走到 `sum.size() - 1` * 這樣 `(j, k)` 就代表一段非空子陣列 * 用 `sum[k] - sum[j]` 得到該段子陣列總和,並用它更新 `ans` ### 3. 回傳答案 * 雙迴圈跑完後,`ans` 就是最大連續子陣列總和 ## 💻 程式碼實作(一) ```cpp 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` 就是最大連續子陣列總和。 ## 💻 程式碼實作(二) ```cpp 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/description/
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up