918. 环形子数组的最大和
考点
- 环形DP
- 最大子数组和
思路
1. 问题描述
给定长度为 \(n\) 的整数数组 \(\texttt{nums}\),数组首尾相接构成一个环。允许选择一个非空的连续子数组(在环上连续,因此可以“跨过末尾回到开头”),求其元素和的最大值。
2. 为什么“不建议拉长成链再 DP”
一种直觉是将数组复制一份,得到长度 \(2n\) 的链: \[ B = \texttt{nums} \;||\; \texttt{nums} \] 然后在链上求“最大子数组和”。但这在环形问题上有一个关键陷阱:
2.1 必须加上“长度不超过 \(n\)”的约束
环形数组中任意合法子数组最多包含 \(n\) 个元素(不能绕圈超过一圈)。而在 \(B\) 上做普通 Kadane/DP:
- 会允许选择长度 \(>n\) 的子数组(相当于绕了超过一圈)
- 得到的最大值可能是非法解
因此,若坚持使用 \(B\),必须显式施加约束: \[ \max \left\{ \sum_{k=l}^{r} B[k] \; \middle| \; 0 \le l \le r < 2n,\; r-l+1 \le n \right\} \] 这会直接带来设计复杂度:
- 朴素 DP:需要额外维度记录长度,典型为 \(O(n^2)\),对 \(n \le 3\times 10^4\) 不可行。
- 前缀和 + 单调队列:可以做到 \(O(n)\),但实现复杂,且本题存在更直接的等价建模(见下文),无需复制数组。
结论:复制数组并不是错,但若没有“长度 \(\le n\)”约束必错;加入约束后要么变成 \(O(n^2)\) 超时,要么写成更复杂的单调队列版本。而本题存在更简洁的 \(O(n)\) 方案。
3. 关键建模:把“跨环”转化为“排除一段”
环形最大子数组和可以分成两类:
- 不跨环:子数组完全在 \([0, n-1]\) 的线性区间内 \(\Rightarrow\) 这就是经典最大子数组和(Kadane)。
- 跨环:子数组从末尾接到开头 \(\Rightarrow\) 这种子数组可以视为:从整段数组中“删掉”中间一段连续区间。
3.1 跨环子数组的等价表达
设跨环子数组为环上的一段连续弧。将其在数组上展开,会形如:
- 取后缀:\(\texttt{nums}[i..n-1]\)
- 再取前缀:\(\texttt{nums}[0..j]\)
其和为: \[ \sum_{k=i}^{n-1} \texttt{nums}[k] \;+\; \sum_{k=0}^{j} \texttt{nums}[k] \] 令总和: \[ S = \sum_{k=0}^{n-1} \texttt{nums}[k] \] 注意到被没有选中的那一段恰好是中间的连续区间: \[ \texttt{nums}[j+1..i-1] \] 因此跨环子数组和等于: \[ S \;-\; \sum_{k=j+1}^{i-1} \texttt{nums}[k] \] 于是跨环情况下要最大化子数组和,就等价于最小化被删掉的那段连续子数组和: \[ \max_{\text{wrap}} = S - \min_{\text{linear subarray}}(\text{sum}) \]
3.2 最终答案结构
令:
- \(\text{mx}\) = 线性最大子数组和
- \(\text{mi}\) = 线性最小子数组和
则候选答案为: \[ \max(\text{mx},\; S - \text{mi}) \] 但要注意一个边界情况:
3.3 “全负数”陷阱:为什么要特判
当数组全为负数时:
- 线性最大子数组和 \(\text{mx} < 0\),此时正确答案应该是“最大的那个负数”(即 Kadane 的结果)。
- 线性最小子数组和 \(\text{mi} = S\)(整段数组就是最小子数组)。
- 若直接用 \(S-\text{mi}\),会得到 \(0\),对应“删掉整段数组、选空集”,但题目要求子数组非空,因此这是非法的。
所以必须特判: \[ \text{若 } \text{mx} < 0,\; \text{答案} = \text{mx};\quad \text{否则答案} = \max(\text{mx}, S-\text{mi}) \]
4. 程序设计思路:一次遍历同时维护最大/最小子数组
本题可以在一次循环中同时做两次 Kadane:
4.1 最大子数组(Kadane)
定义:
- \(\text{pmx}\):以当前位置结尾的最大子数组和(previous max ending here)
- 转移:
\[ \text{pmx} \leftarrow \max(\texttt{nums}[i],\; \text{pmx} + \texttt{nums}[i]) \]
并维护全局最大: \[ \text{mx} \leftarrow \max(\text{mx},\; \text{pmx}) \]
4.2 最小子数组(Kadane 的对偶)
同理:
- \(\text{pmi}\):以当前位置结尾的最小子数组和
- 转移:
\[ \text{pmi} \leftarrow \min(\texttt{nums}[i],\; \text{pmi} + \texttt{nums}[i]) \]
并维护全局最小: \[ \text{mi} \leftarrow \min(\text{mi},\; \text{pmi}) \]
4.3 总和同时累积
\[ S \leftarrow S + \texttt{nums}[i] \]
4.4 复杂度
- 时间复杂度:\(\;O(n)\)
- 空间复杂度:\(\;O(1)\)
5. 参考实现(对用户 AC 代码加注释)
1 | class Solution { |