原始题目
下面这段代码横线处应该填什么?
int maxSubArray(int a[], int n) {
int currentSum = a[0];
int maxSum = a[0];
for (int i = 1; i < n; i++) {
currentSum = max(a[i], ___);
maxSum = max(maxSum, currentSum);
}
return maxSum;
}
- A.
currentSum - B.
currentSum + a[i] - C.
maxSum + a[i] - D.
a[i]
答案:B(
currentSum + a[i])
完整写法(Kadane 算法,一维 DP):
int maxSubArray(int a[], int n) {
int currentSum = a[0];
int maxSum = a[0];
for (int i = 1; i < n; i++) {
currentSum = max(a[i], currentSum + a[i]); // 另起炉灶 vs 接着续
maxSum = max(maxSum, currentSum);
}
return maxSum;
}
图解:另起炉灶还是接着续
以经典数据 {-2, 1, -3, 4, -1, 2, 1, -5, 4} 为例(绿色是最大子段,红点是“另起炉灶”的位置):
状态含义
currentSum 表示以 i 结尾的最大子段和。到了第 i 个元素只有两种选择:
- 另起炉灶:从
a[i]重新开始(前面的和是累赘时) - 接着续:把
a[i]接到前面的子段后面,即currentSum + a[i]
两者取大。若 currentSum 为负,a[i] 单干必然更优——这就是「前面的和为负就果断丢弃」的贪心本质。
手动模拟
| i | a[i] | currentSum = max(a[i], currentSum+a[i]) | maxSum |
|---|---|---|---|
| 0 | -2 | -2(初始) | -2 |
| 1 | 1 | max(1, -2+1) = 1(另起炉灶) | 1 |
| 2 | -3 | max(-3, 1-3) = -2 | 1 |
| 3 | 4 | max(4, -2+4) = 4(另起炉灶) | 4 |
| 4 | -1 | max(-1, 4-1) = 3 | 4 |
| 5 | 2 | max(2, 3+2) = 5 | 5 |
| 6 | 1 | max(1, 5+1) = 6 | 6 |
| 7 | -5 | max(-5, 6-5) = 1 | 6 |
| 8 | 4 | max(4, 1+4) = 5 | 6 |
输出 6,对应子段 [4, -1, 2, 1]。
逐项排除
| 选项 | 判断 | 错在哪 |
|---|---|---|
A. currentSum |
❌ | 丢了 a[i],当前元素没参与,等于没更新 |
B. currentSum + a[i] |
✅ | 延续前面的子段,与“另起炉灶”的 a[i] 取大 |
C. maxSum + a[i] |
❌ | 混淆变量:maxSum 是全局最优,不以 i 结尾,接不上 |
D. a[i] |
❌ | 永远另起炉灶,等于只找单个最大元素 |
初始化:最容易踩的坑
int currentSum = a[0], maxSum = a[0]; // ✅ 正确
// int currentSum = 0, maxSum = 0; // ❌ 全负数组会错
若初始化为 0,输入 {-3, -1, -2} 时会输出 0,而正确答案是 -1(题目要求子段非空)。循环也必须从 i = 1 开始。
复杂度
| 方法 | 时间 | 空间 |
|---|---|---|
| 暴力枚举 | \(O(n^2)\) / \(O(n^3)\) | \(O(1)\) |
| 前缀和 + 最小前缀 | \(O(n)\) | \(O(n)\) |
| Kadane(本题) | \(O(n)\) | \(O(1)\) |
Kadane 只需一次线性扫描、两个变量,是 DP 入门必背模型。
考点总结(CSP-J/S 初赛、程序填空)
- 见到
max(a[i], currentSum + a[i])结构 → 最大子段和 / Kadane。 currentSum的定义必须带「以 i 结尾」,否则递推不成立。- 初始化用
a[0],不能是 0(全负数组陷阱)。 - 每步都要
maxSum = max(maxSum, currentSum),答案在全局里取,不是最后的currentSum。
思考题
数组 {-3, -1, -2} 用上面的代码跑出来是多少?如果题目要求「子段可以为空,空子段和为 0」,该改哪一行?
答案
跑出来是 -1(取单个元素 -1)。若允许空子段,把初始化改成 currentSum = 0; maxSum = 0; 且循环从 i = 0 开始即可,此时全负数组答案为 0。
![BFS 为什么能求最短路?—— dist[v] = dist[u] + 1 与分层思想](https://gesp-img.oss-accelerate.aliyuncs.com/uploads/202609/13/199d2ea51279b83f.png)


