分治法比暴力法快是因为避免重复计算,时间复杂度为O(n log n);关键在“治”阶段高效计算跨中点的最大子数组和,需正确初始化left_sum/right_sum为INT_MIN,递归终止条件必须是left == right。

最大子数组和的分治实现为什么比暴力快?
因为避免了重复计算:暴力法对每个起点都重算和,时间复杂度是 O(n²);分治把数组一劈为二,只在跨越中点时集中处理一次,递归式是 T(n) = 2T(n/2) + O(n),解出来是 O(n log n)。
关键不在“分”,而在“治”——合并左右两半时,必须高效算出以中点为右端的最大左子数组和、以中点+1为左端的最大右子数组和。这两部分加起来,才是跨中点的候选答案。
常见错误现象:left_sum 或 right_sum 初始化成 0,导致空子数组被误选(比如全负数时返回 0,但题目通常要求至少选一个元素);正确做法是初始化为 INT_MIN 或直接用第一个元素。
- 使用场景:数组无特殊限制,但需要严格
O(n log n)时间且不能用动态规划(比如教学演示、面试限定解法) - 参数差异:
maxSubArrayHelper(nums, left, right)必须传闭区间,mid = left + (right - left) / 2防溢出 - 性能影响:常数因子比 Kadane 算法大 3–5 倍,小数组(
n )可能更慢
跨中点最大和怎么写才不越界?
核心是两个独立的单向扫描:从 mid 往左,累加并更新 left_max;从 mid + 1 往右,累加并更新 right_max。边界检查只发生在循环条件里,不是每次访问前判断。
立即学习“C++免费学习笔记(深入)”;
容易踩的坑:for (int i = mid; i >= left; --i) 写成 i > left 漏掉 left 位置;或者 right 边界用开区间导致 nums[right] 访问越界。
简短示例:
int left_sum = INT_MIN, sum = 0;
for (int i = mid; i >= left; --i) {
sum += nums[i];
left_sum = max(left_sum, sum);
}
递归终止条件写 left == right 还是 left > right?
必须是 left == right。因为子数组长度至少为 1,单个元素就是它自己,直接返回 nums[left]。
如果写成 left > right 返回 0 或 INT_MIN,会导致递归多一层、逻辑断裂,而且无法处理 n == 1 的输入。
- 兼容性影响:所有标准 C++ 编译器(GCC、Clang、MSVC)都支持该写法,无差异
- 调试提示:加一句
assert(left 能早发现调用错位
为什么不能直接返回 max({left_max, right_max, cross_max})?
可以,但前提是三个变量都已正确定义。常见错误是漏算 cross_max,或把 left_max 和 right_max 当成“包含中点”的值来用——它们实际只是左右半边各自的最大子数组和,不一定连着中点。
真正要比较的是:maxSubArrayHelper(nums, left, mid)、maxSubArrayHelper(nums, mid + 1, right)、cross_sum。这三个值语义一致,都是“对应区间内的最大子数组和”,才能安全取最大。
容易被忽略的点:cross_sum 是临时算出来的,它不等于 left_max + right_max(虽然数值上相等),而是由两个方向扫描共同决定的。一旦中间某个数极大,它就主导结果,和左右两边内部结构无关。










