题目链接
题目描述
{6, -3, -2, 7, -15, 1, 2, 2},连续子数组的最大和为 8(从第 0 个开始,到第 3 个为止)。
解题思路
动态规划解析:
状态定义: 设动态规划列表 dp ,dp[i] 代表以元素 nums[i] 为结尾的连续子数组最大和。
- 为何定义最大和 dp[i] 中必须包含元素 nums[i] :保证 dp[i] 递推到 dp[i+1] 的正确性;如果不包含 nums[i] ,递推时则不满足题目的 连续子数组 要求。
转移方程: 若 dp[i−1]≤0 ,说明 dp[i−1] 对 dp[i] 产生负贡献,即 dp[i−1]+nums[i] 还不如 nums[i] 本身大。
- 当 dp[i−1]>0 时:执行dp[i]=dp[i−1]+nums[i] ;
- 当 dp[i−1]≤0 时:执行 dp[i]=nums[i] ;
- 初始状态: dp[0]=nums[0],即以 nums[0] 结尾的连续子数组最大和为 nums[0] 。
返回值: 返回 dp 列表中的最大值,代表全局最大值。
空间复杂度降低:
- 由于 dp[i] 只与 dp[i-1] 和 nums[i] 有关系,因此可以将原数组 nums 用作 dp 列表,即直接在 nums 上修改即可。
- 由于省去 dp 列表使用的额外空间,因此空间复杂度从 O(N) 降至 O(1) 。
class Solution {
public:
int FindGreatestSumOfSubArray(vector<int> array) {
int n = array.size();
if(n==0)
return 0;
int max,dp;
max = dp = array[0];
for(int i=1;i<n;i++){
if(dp<0)
dp = array[i];
else
dp=dp+array[i];
max = dp>max?dp:max;
}
return max;
}
};
- 时间复杂度 O(N) : 其中 N 为字符串长度,动态规划需遍历计算 dp 列表。
- 空间复杂度 O(1)
返回最大和的子数组
class Solution {
public int[] maxSubArray(int[] nums) {
// right为当前最大和的子数组右坐标
// s为子数组长度
// count为子数组中间计数
int right = 0, s = 0, count = 0;
// 利用dp不改变原始数组
int[] dp = new int[nums.length];
dp[0] = nums[0];
for(int i = 1; i < nums.length; ++i){
if(nums[i] < nums[i] + dp[i-1]){
dp[i] = nums[i] + dp[i-1];
// 连续 计数加一
++count;
}else{
dp[i] = nums[i];
// 断开连续,重新计数
count = 0;
}
if(dp[i] > dp[right]){
// 出现更大的值,记录子数组右坐标和长度
right = i;
s = count;
}
}
// 复制右坐标
int[] res = new int[s + 1];
for(int i = right - s, j = 0; i <= right; ++i,++j){
res[j] = nums[i];
}
return res;
}
}