20230227 1.3. 应用实例
最大子列和问题
给定N个整数的序列 \({ A_1, A_2, …, A_N}\) ,求函数 \(f(i,j)=max\{0,\sum_{k=i}^jA_k\}\) 的最大值。
算法1:直接法
int MaxSubseqSum1(int A[], int N) {
int ThisSum, MaxSum = 0;
int i, j, k;
for (i = 0; i < N; i++) { /* i是子列左端位置 */
for (j = i; j < N; j++) { /* j是子列右端位置 */
ThisSum = 0; /* ThisSum是从A[i]到A[j]的子列和 */
for (k = i; k <= j; k++) {
ThisSum += A[k];
}
if (ThisSum > MaxSum) /* 如果刚得到的这个子列和更大 */ {
MaxSum = ThisSum; /* 则更新结果 */
}
} /* j循环结束 */
} /* i循环结束 */
return MaxSum;
}
\(T( N ) = O( N^3 )\)
算法2:优化
int MaxSubseqSum2(int A[], int N) {
int ThisSum, MaxSum = 0;
int i, j;
for (i = 0; i < N; i++) { /* i是子列左端位置 */
ThisSum = 0; /* ThisSum是从A[i]到A[j]的子列和 */
for (j = i; j < N; j++) { /* j是子列右端位置 */
ThisSum += A[j];
/*对于相同的i,不同的j,只要在j-1次循环的基础上累加1项即可*/
if (ThisSum > MaxSum) /* 如果刚得到的这个子列和更大 */ {
MaxSum = ThisSum; /* 则更新结果 */
}
} /* j循环结束 */
} /* i循环结束 */
return MaxSum;
}
\(T( N ) = O( N^2 )\)
算法3:分治法
int MaxSubseqSum3(int A[], int N) {
return maxsub(A, 0, N - 1);
}
int maxsub(int a[], int left, int right) {
// 递归出口 ,当只有一个元素的时候,大于0的将其返回,否则返回0
if (left == right) {
if (a[left] > 0) {
return a[left];
} else {
return 0;
}
}
int mid = (left + right) / 2;// 找到中点
// 分的过程
int maxLeft = maxsub(a, left, mid);
int maxRight = maxsub(a, mid + 1, right);
// 求跨界,该子列包括 a[mid],所以由mid为中心向两边求跨界的最大子列和
int borderLeft = 0;
int borderRight = 0;
int sumLeft = 0;
int sumRight = 0;
// 由中点mid向左扫描
for (int i = mid; i >= left; i--) {
borderLeft += a[i];
if (borderLeft > sumLeft)// 向左更新左边最大子列和
{
sumLeft = borderLeft;
}
}
// 由中点mid向右扫描
for (int i = mid + 1; i <= right; i++) {
borderRight += a[i];
if (borderRight > sumRight)// 向右更新右边的最大子列和
{
sumRight = borderRight;
}
}
// sumRight+sumLeft为该范围跨界的最大子列和
// maxLeft为left到mid范围内的最大子列和
// maxRight为mid+1到right的最大子列和
// 返回三者的最大值
return Math.max(Math.max(maxLeft, maxRight), sumRight + sumLeft);
}
\(T ( N ) = O( N log N )\)
算法4:在线处理
int MaxSubseqSum4(int A[], int N) {
int ThisSum, MaxSum;
ThisSum = MaxSum = 0;
for (int i = 0; i < N; i++) {
ThisSum += A[i]; /* 向右累加 */
if (ThisSum > MaxSum) {
MaxSum = ThisSum; /* 发现更大和则更新当前结果 */
} else if (ThisSum < 0) /* 如果当前子列和为负 */ {
ThisSum = 0; /* 则不可能使后面的部分和增大,抛弃之 */
}
}
return MaxSum;
}
“在线”的意思是指每输入一个数据就进行即时处理,在任何一个地方中止输入,算法都能正确给出当前的解。
\(T( N ) = O( N )\)