连续子数组的最大和
题目
输入一个 非空 整型数组,数组里的数可能为正,也可能为负。
数组中一个或连续的多个整数组成一个子数组。
求所有子数组的和的最大值。
要求时间复杂度为 O(n)。
数据范围
数组长度 [1,1000]。
数组内元素取值范围 [−200,200]。样例
输入:[1, -2, 3, 10, -4, 7, 2, -5] 输出:18
-
算法标签
- 动态规划
- 贪心
解法1:动态规划
- 令 d p [ i ] dp[i] dp[i]为以 n u m s [ i ] nums[i] nums[i]为结尾的子数组中求和最大的子数组
- 有两种可能的转移,一种不要 i i i前面的子数组,从 n u m s [ i ] nums[i] nums[i]开始为新的子数组;一种是和 n u m s [ i − 1 ] nums[i-1] nums[i−1]以及其前面的数构成一个子数组,两种情况取max
- 状态转移方程:
d p [ i ] = m a x { d p [ i − 1 ] + n u m s [ i ] n u m s [ i ] dp[i]=max\begin{cases} dp[i-1]+nums[i]\\ nums[i] \end{cases} dp[i]=max{ dp[i−1]+nums[i]nums[i]
- 答案:
max 0 ≤ i ≤ n d p [ i ] \max_{0\le i\le n} dp[i] 0≤i≤nmaxdp[i]
//dp
class Solution {
public:
const int N=1005;
int maxSubArray(vector<int>& nums) {
int dp[N];
int ans=-205;
for(int i=0;i<nums.size();i++){
dp[i]=nums[i];
if(i)dp[i]=max(dp[i],dp[i-1]+nums[i]);
ans=max(ans,dp[i]);
}
return ans;
}
};
解法2:贪心
- 考虑第 i i i个数 n u m s [ i ] nums[i] nums[i]的时候,用一个 s u m sum sum记录前 i − 1 i-1 i−1个数累计的最大连续子数组合
- 如果 s u m < 0 sum<0 sum<0则说明对子数组的求和没用贡献,可以丢弃,从 n u m s [ i ] nums[i] nums[i]开始新的子数组;否则则可以加上 s u m sum sum
- 使用一个 a n s = max i s u m i ans=\max_i sum_i ans=maxisumi记录答案,因为 s u m sum sum有可能在中间取得最大值随后又变小
- 注意 a n s ans ans的初始化要从下界开始而不是 0 0 0
//贪心
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int sum=0,ans=-205;
for(int i=0;i<nums.size();i++){
if(sum<0) sum=nums[i];
else sum+=nums[i];
ans=max(ans,sum);
}
return ans;
}
};