动态规划:子数组与子串问题
一、最大子数组和
这道题要求找到数组中连续子数组的最大和。核心在于思考以第 i 个元素结尾的子数组,是延续前面的结果,还是从当前重新开始。

我们定义 dp[i] 为以第 i 个元素结尾的连续子数组的最大和。对于每个位置,只有两种选择:要么把当前元素加到前一个子数组后面(如果前一个和是正的),要么直接从当前元素开始新的一段。状态转移方程就是 dp[i] = max(dp[i-1] + nums[i], nums[i])。
初始化时,dp[0] 就是第一个元素本身。遍历过程中,我们需要维护一个全局最大值 ret,因为最终答案不一定是以最后一个元素结尾的。
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int n = nums.size();
vector<int> dp(n, 0);
dp[0] = nums[0];
int ret = dp[0];
for (int i = 1; i < n; i++) {
dp[i] = max(dp[i - 1] + nums[i], nums[i]);
ret = max(ret, dp[i]);
}
return ret;
}
};
二、环形子数组的最大和
数组变成环形后,最大子数组有两种可能:一种是普通的非环形子数组,另一种是跨越首尾的环形子数组。后者实际上等于总和减去中间那段最小子数组的和。

我们需要同时计算两个 DP 数组:f[i] 记录以 i 结尾的最大子数组和, 记录以 i 结尾的最小子数组和。遍历结束后,比较普通情况下的最大值 和环形情况下的 。注意一种特殊情况:如果所有数都是负数,最小子数组和等于总和,此时不能取环形结果,应直接返回 。








