给定N个整数序列{A1,A2,A3,...,An},求出子序列(例:Ai-Aj,必须是连续的)中的最大值

题目:给定N个整数序列{A1,A2,A3,...,An},求出子序列(例:Ai-Aj,必须是连续的)中的最大值

下面给出此题的四种解决办法,且时间复杂度依次增加。

  • 方法一
 public int maxSubsequenceSum4(int[] list, int n){
        int thisSum = 0;//当前子序列和
        int maxSum = 0;//目前最大子序列和
        for (int i = 0; i < n; i++){
          thisSum += list[i];
          if (thisSum > maxSum){//当发现更大的子序列和时,替换此前的和
              maxSum = thisSum;
          }
         /*当当前子序列和加上一个绝对值大于它的负数时,此子序列变成负数,
          *此时应当抛弃该子序列,重新以下一个整数为开头寻找下一个子序列.
          *例如:1,3,-5,4,2,-1,...
          *显然子序列A1,A2,A3的和为负数,此时应当抛弃A1,A2,A3...(注意:此时maxSum为A1,A2的和)
          *并以A4...开始寻找下一个合适的子序列
          *
          */
          else if (thisSum < 0){
              thisSum = 0;
          }
        }
        return maxSum;
    }
  • 方法二
 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];//子序列为list[center],list[center-1],...
            if( LeftBorderSum > MaxLeftBorderSum )
                MaxLeftBorderSum = LeftBorderSum;
        } /* 左边扫描结束 */

        MaxRightBorderSum = 0; RightBorderSum = 0;
        for( i=center+1; i<=right; i++ ) { /* 从中线向右扫描 */
            RightBorderSum += list[i];//子序列为list[center+1],list[center+2],...
            if( RightBorderSum > MaxRightBorderSum )
                MaxRightBorderSum = RightBorderSum;
        } /* 右边扫描结束 */

        /* 下面返回"治"的结果 */
        return Max3( MaxLeftSum, MaxRightSum, MaxLeftBorderSum + MaxRightBorderSum );
    }

    int maxSubsequenceSum3(int[] list, int N )
    { /* 保持与前2种算法相同的函数接口 */
        return DivideAndConquer( list, 0, N-1 );
    }

同样举例说明方法二

4-35-2-126-2

以上为八个整数序列,下面用方法二求出八个整数序列的最大子序列
函数执行顺序图如下:

函数执行顺序图
递归先由最后分割到不可再分时,求出分割线两侧数据的值

if( left == right )  { /* 递归的终止条件,子列只有1个数字 */
            if( list[left] > 0 )  return list[left];
            else return 0;
        }

然后再返回上一层调用函数,求出左右两部分的子序列最大值。注意:分割线两侧数据为起始数据
该方法主要就是以分割线两侧数据为起始数据,两边分散(不中断)求左右子序列的和
最后跨分割线子序列最大值左侧最大值+右侧最大值(例如:(A1,A2,A3,A4),左侧:A1,A2右侧:A3,A4.假设其左侧最大子序列和为A2,A1,右侧大子序列和为A3,则跨分割线子序列最大值为A1,A2,A3)

/* 下面求跨分界线的最大子列和 */
        MaxLeftBorderSum = 0; LeftBorderSum = 0;
        for( i=center; i>=left; i-- ) { /* 从中线向左扫描 */
            LeftBorderSum += list[i];//子序列为list[center],list[center-1],...
            if( LeftBorderSum > MaxLeftBorderSum )
                MaxLeftBorderSum = LeftBorderSum;
        } /* 左边扫描结束 */

        MaxRightBorderSum = 0; RightBorderSum = 0;
        for( i=center+1; i<=right; i++ ) { /* 从中线向右扫描 */
            RightBorderSum += list[i];//子序列为list[center+1],list[center+2],...
            if( RightBorderSum > MaxRightBorderSum )
                MaxRightBorderSum = RightBorderSum;
        } /* 右边扫描结束 */

最后返回三个数据的最大值,即最大子序列和

        /* 下面返回"治"的结果 */
        return Max3( MaxLeftSum, MaxRightSum, MaxLeftBorderSum + MaxRightBorderSum );
  • 方式三
public int maxSubsequenceSum2(int[] list, int n){
        int thisSum = 0;
        int maxSum = 0;
        for (int i = 0; i < n; i++){//循环n次,每次循环表示以Ai为子序列的起始数据
            thisSum = 0;
            for (int j = i; j < n; j++){
                    thisSum += list[j];//子序列为Ai,Ai+1,...
                    if (thisSum > maxSum){
                        maxSum = thisSum;
                    }
            }
        }
        return maxSum;
    }
  • 方法四

时间复杂度T(n)=n3

public int maxSubsequenceSum1(int A[],int n){
        int thisSum = 0;
        int maxSum = 0;
        for (int i = 0; i < n; i++){
            for (int j = i; j < n; j++){
                thisSum = 0;
                for (int k = i; k <= j; k++ ){
                    thisSum += A[k];
                    if (thisSum > maxSum){
                        maxSum = thisSum;
                    }
                }
            }
        }
        return maxSum;
    }

代码来自MOOC网浙江大学数据结构课程,本人稍作修改整理以及加上自己的解释

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值