20230227 1.3. 应用实例

发布时间 2023-06-21 16:27:27作者: 流星<。)#)))≦

最大子列和问题

给定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 )\)