给定一个有正有负的整数数组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; } };