问题
输出最大子列和。
如果序列中所有整数皆为负数,则输出0。(没这个要求也可以做,本文针对这种情况)
算法1
最容易想到,也是最笨的方法,把所以子列和都算出来,找到最大的。
/* 方法一:所有子列和都算出来,保留最大值 */
int maxSubSeqSum1(int a[], int n)
{
int sum = 0;
int max = 0;
for (int i = 0; i < n; i++) /* i是子列左端位置*/
{
for (int j = i; j < n; j++) /* j是子列右端位置*/
{
sum = 0; /* i1_sum是从A[i]到A[j]的子列和*/
for (int k = i; k <= j; k++)
{
sum += a[k];
}
if (sum > max)
{
max = sum;
}
}
}
return max;
}
显然,T(N) = O(N^3)
算法2
在算法1的基础上优化了求i到j子列和。
/* 方法二:对于相同的子列左端位置 i ,不同的右端位置 j ,我们只要每次在右端累加一项,即可求得每一个子列和。 */
int maxSubSeqSum2(int a[], int n)
{
int sum = 0;
int max = 0;
for (int i = 0; i < n; i++) /* i是子列左端位置*/
{
sum = 0;
for (int j = i; j < n; j++) /* j是子列右端位置*/
{
sum += a[j]; /* 对于相同的i,不同的j,只要在j-1次循环的基础上累加1项即可 */
if (sum > max)
{
max = sum;
}
}
}
return max;
}
显然,T(N)=O(N^2)
算法3
分而治之。
跨界最大值:1. 找到从中间往左走的最大值;
2. 找到从中间往右走的最大值;
3. 左+右。
int Max3(int A, int B, int C)
{ /* 返回3个整数中的最大值 */
return A > B ? A > C ? A : C : B > C ? B : C;
}
int DivideAndConquer(int List[], int left, int right)
{ /* 分治法求List[left]到List[right]的最大子列和 */
int MaxLeftSum, MaxRightSum; /* 存放左右子问题的解 */
int MaxLeftBorderSum, MaxRightBorderSum; /*存放跨分界线的结果*/
int LeftBorderSum, RightBorderSum;
int center, i;
if (left == right)
{ /* 递归的终止条件,子列只有1个数字 */
if (List[left] > 0)
{
return List[left];
}
else
{
return 0;
}
}
/* 下面是"分"的过程 */
center = (left + right) / 2; /* 找到中分点 */
/* 递归求得两边子列的最大和 */
MaxLeftSum = DivideAndConquer(List, left, center);
MaxRightSum = DivideAndConquer(List, center + 1, right);
/* 下面求跨分界线的最大子列和 */
MaxLeftBorderSum = 0;
LeftBorderSum = 0;
for (i = center; i >= left; i--)
{ /* 从中线向左扫描 */
LeftBorderSum += List[i];
if (LeftBorderSum > MaxLeftBorderSum)
MaxLeftBorderSum = LeftBorderSum;
} /* 左边扫描结束 */
MaxRightBorderSum = 0;
RightBorderSum = 0;
for (i = center + 1; i <= right; i++)
{ /* 从中线向右扫描 */
RightBorderSum += List[i];
if (RightBorderSum > MaxRightBorderSum)
MaxRightBorderSum = RightBorderSum;
} /* 右边扫描结束 */
/* 下面返回"治"的结果 */
return Max3(MaxLeftSum, MaxRightSum, MaxLeftBorderSum + MaxRightBorderSum);
}
/* 方法三:分而治之 */
int maxSubSeqSum3(int a[], int n)
{ /* 保持与前2种算法相同的函数接口 */
return DivideAndConquer(a, 0, n - 1);
}
算法4
“在线”的意思是指每输入一个数据就进行即时处理,在任何一个地方中止输入,算法都能正确给出当前的解。
/* 方法四:在线处理 */
int maxSubSeqSum4(int a[], int n)
{
int maxSum = 0;
int curSum = 0;
for (int i = 0; i < n; i++)
{
curSum += a[i];
if (curSum > maxSum)
{
/* 发现更大的和则更新 */
maxSum = curSum;
}
else if (curSum < 0)
{
/* 小于0就丢弃,往后累加只会让和变小 */
curSum = 0;
}
}
return maxSum;
}