给定一个有正有负的整数数组A及其大小n,返回从前往后相加最大的连续数列的和。保证n的大小小于等于3000。
测试样例:
[1,2,3,-6,1]
返回:6
时间复杂度O(n),空间复杂度O(1),动态规划
class MaxSum {
public:
int getMaxSum(vector<int> A, int n) {
// write code here
int dp0 = A[0], max = A[0];
for(int i = 1; i < n; i++)
{
if(dp0 + A[i] > A[i])
dp0 = dp0 + A[i];
else
dp0 = A[i];
if(dp0 > max)
max = dp0;
}
return max;
}
};
int getMaxSum(vector<int> A, int n) {
// write code here
int cur_sum, max_sum = INT_MIN;
for (int i = 0; i < n; i++) // i是子列左端位置
{
cur_sum = 0; // this_sum是子列A[i]...A[j]的和
for (int j = i; j < n; j++) // j是子列右端位置
{
cur_sum += A[j];
if (cur_sum > max_sum)
max_sum = cur_sum;
}
}
return max_sum;
} int getMaxSum(vector<int> A, int n) {
// write code here
return maxSumRec(A, 0, n - 1);
}
int maxSumRec(vector<int> A, int left, int right) // 递归求解,复杂度O(nlogn)
{
if (left == right) // 递归终止条件,子列只有1个数字
return A[left];
/* 下面是"分"的过程 */
int mid = (left + right) / 2;
int maxLeftSum = maxSumRec(A, left, mid); // 递归求解左半部分
int maxRightSum = maxSumRec(A, mid + 1, right); // 递归求解右半部分
/* 下面求跨分界线的最大子列和 */
// 求出左半部分包含最后一个元素的最大子序列和
int leftBorderSum = 0, maxLeftBorderSum = INT_MIN;
for (int i = mid; i >= left; i--) // 从中线向左扫描
{
leftBorderSum += A[i];
if (leftBorderSum > maxLeftBorderSum)
maxLeftBorderSum = leftBorderSum;
}
// 求出右半部分包含第一个元素的最大子序列和
int rightBorderSum = 0, maxRightBorderSum = INT_MIN;
for (int j = mid + 1; j <= right; j++) // 从中线向右扫描
{
rightBorderSum += A[j];
if (rightBorderSum > maxRightBorderSum)
maxRightBorderSum = rightBorderSum;
}
return max3(maxLeftSum, maxRightSum, maxLeftBorderSum + maxRightBorderSum);
}
int max3(int a, int b, int c) // 求出三者中的最大值
{
int max = a;
if (max < b) max = b;
if (max < c) max = c;
return max;
} int getMaxSum(vector<int> A, int n) {
// write code here
int cur_sum = 0, max_sum = INT_MIN;
for (int i = 0; i < n; i++)
{
cur_sum += A[i]; // 向右累加
if (cur_sum > max_sum)
max_sum = cur_sum; // 发现更大和则更新当前结果
if (cur_sum < 0) // 如果当前子列和为负
cur_sum = 0; // 则不可能作为最大子列的前缀,扔掉
}
return max_sum;
} import java.util.*;
/*
思路:从第一个数开始加,如果加上这个数的和小于0,那就从下一个数重新开始加,记录过程中出现的最大值即可
我觉得这道题目是可以推广到计算最大值对应的连续数列区间,计算区间就需要保存每次max值变更的时候的start
和end位置
*/
public class MaxSum {
public int getMaxSum(int[] A, int n) {
int max=A[0];
int sum=0;
for(int i=0;i<n;i++){
sum+=A[i];
max=Math.max(sum,max);
if(sum<0) sum=0;
}
return max;
}
}
运行时间:92ms
占用内存:11460k
class MaxSum {
public:
int getMaxSum(vector<int> A, int n) {
if(n<=0){
return 0;
}
int temp = A[0];
int max = A[0];
for(int i=1; i<n; i++){
if(temp>=0){
temp += A[i];
if(temp>0){
if(temp>max){
max = temp;
}
}else{
temp = 0;
}
}else{
if(A[i]>0){
temp = A[i];
max = temp;
}else{
if(temp < A[i]){
temp = A[i];
max = temp;
}
}
}
}
return max;
}
};
# -*- coding:utf-8 -*-
class MaxSum:
def getMaxSum(self, A, n):
if n < 1:
return 0
sum = A[0]
max = A[0]
for i in range(1, n):
if sum < 0:
sum = A[i]
else:
sum += A[i]
if max < sum:
max = sum
return max
class MaxSum {
public:
int getMaxSum(vector<int> A, int n) {
// write code here
if(n<=0) return 0;
if(n==1) return A[0];
int sum=A[0];
int curmax=A[0];
int i;
for(i=1;i<A.size();i++)
{
curmax=(curmax<0)?A[i]:curmax+A[i];
sum=(curmax>sum)?curmax:sum;
}
return sum;
}
};
/*
思路1:动态规划
状态定义:
F[i]:以i下标为结尾的子序列的最大和
在子序列的求和过程中,遵循的原则是,如果加上某个数对最大和有利那么就加上,如果不利就不加。
因此以i下标为结尾的子序列的最大和 = max(以i-1为下标的子序列的和+A[i],A[i])
也就是说,如果A[i]加上前一个子序列,所得值反而小于A[i]本身,那么干脆就让A[i]自身作为一个新的最大子序列。
状态转移方程:
F[i] = max(F[i-1]+A[i],A[i]);
状态初始化:
F[0] = A[0]
*/
/*
class MaxSum {
public:
int getMaxSum(vector<int> A, int n) {
//校验数据合法性
if(A.size()==0 || n<=0){
return 0;
}
vector<int> F(n);
F[0] = A[0];
//状态转移方程
for(int i=1;i<n;i++){
F[i] = max(F[i-1]+A[i],A[i]);
}
//排升序,便于获取最大和
sort(F.begin(),F.end());
return F[n-1];
}
};
*/
/*
思路2:贪心
其实和动态规划类似:有利于我的我就要,不利于我的我不要
*/
class MaxSum {
public:
int getMaxSum(vector<int> A, int n) {
//校验数据合法性
if(A.size()==0 || n<=0){
return 0;
}
//防止数组全是负数
int sum = A[0];
int totalSum = A[0];
//从第二个元素开始
for(int i=1;i<n;i++){
if((sum+A[i]) >= A[i]){
//当前数加上前一个数组的最大和有利于当前数,因此加上
sum += A[i];
}else{
//当前数加上前一个数组的最大和不利于当前数,因此当前数重新作为一个数组的开头开始找
sum = A[i];
}
//每找完一个树,都要判断最大值
totalSum = max(totalSum,sum);
}
return totalSum;
}
};
思路:时间复杂度O(n),空间复杂度O(1) 1.首先定义一个和的最小值 2.遍历开始累加 一开始是最小值 ,所以 sum += A[0];sum > max; max 就为A[0]; 判断如果sum 是小于0,重置sum = 0, (累加的初始值还应从0 开始),因为我们把值存在了max中,所以sum 重置为0 不影响max的变化,所以每次比较 sum 和 max 就好 3.这种解法 还有利于求解 产生最大值的区间位置 4.区间位置:就是最后一次更新 sum = 0时,和最后一次max 更新时的位置 即可 int getMaxSum(vector<int> A, int n) { // write code here int sum = 0; int max = -(1 << 30); for(int i=0;i<n;i++) { sum += A[i]; if(sum > max) { max = sum; } if(sum < 0) { sum = 0; } } return max; }