CSES Problem Set — Maximum Subarray Sum 題解
===
題目
---
給一個整數陣列,你的任務是找到最大的非空連續子陣列總和。
### 輸入
- 第一行有一個整數 $n$。($1 \le n \le 2 \cdot 10^5$)
- 第二行有 $n$ 個整數 $x_i$。($-10^9 \le x_i \le 10^9$)
### 輸出
輸出最大的非空連續子陣列總和。
範例測資
---
```
Input:
8
-1 3 -2 5 3 -5 2 2
Output:
9
```
最大總和發生在連續子陣列 $(3, -2, 5, 3)$,總和為 $3 + (-2) + 5 + 3 = 9$。
想法:Kadane 算法
---
> 下面我們將「非空連續子陣列」簡稱為「子陣列」。
假設題目輸入的陣列為 $(x_i)_{i=0}^n$,令 $m$ 為最大的子陣列總和,又令 $c_k$ 為最大的 $x_k$ 結尾子陣列總和,也就是說
\begin{align*}
m &= \max\Bigr\{\sum_{i=a}^b x_i \Bigm| 1\le a \le b \le n\Bigl\},\\
c_k &= \max\Bigr\{\sum_{i=a}^k x_i \Bigm| 1\le a \le k\Bigl\}.
\end{align*} 那麼很直接地就可以看出 $m = \max\{c_b \mid 1 \le b \le n\}$。那麼 $c_k$ 怎麼求呢?
假設以 $x_k$ 結尾的子陣列中,有最大總和 $c_k$ 的是子陣列 $(x_a, \dots, x_k)$。
如果 $a < k$,那麼我們就會發現子陣列 $(x_a, \dots, x_{k-1})$ 同時也會是以 $x_{k-1}$ 結尾的子陣列中有最大總和的那個,換句話說,子陣列 $(x_a, \dots, x_{k-1})$ 的總和是 $c_{k-1}$。這不難驗證,因為若 $(x_b, \dots, x_{k-1})$ 有更大的總和,那麼 $(x_b, \dots, x_k)$ 的總和也將會比 $c_k$ 大而產生矛盾。於是我們有 $c_k = c_{k-1} + x_k$。
除此之外,還有一種可能情況是 $a = k$,也就是說以 $x_k$ 結尾的子陣列中有最大總和的是單元素的子陣列 $(x_k)$,而且 $c_k = x_k$。
所以我們就可以總結出 $c_k = \max(c_{k-1} + x_k, x_k)$。(令 $c_0 = 0$)
我們只要按照 $k=1$ 到 $k=n$ 的順序計算 $c_k$,並隨時記錄最大值 $m$ 就好。又因為 $c_k$ 的計算只依賴於 $c_{k-1}$ 與 $x_k$,這個演算法的時間複雜度是 $O(n)$、空間複雜度是 $O(1)$。
### 範例程式碼
```cpp=
#include <iostream>
using namespace std;
int main() {
int n, x;
int max_sum = -1e9;
int curr_sum = 0;
cin >> n;
for (int k = 1; k <= n; k++) {
cin >> x;
curr_sum = max(curr_sum + x, x);
max_sum = max(max_sum, curr_sum);
}
cout << max_sum;
}
```
---
回 [「CSES題解集」](https://hackmd.io/MpE3CP9eQUu20n3scMF5Fw?view)