求最大子列和的四种算法

本文详细介绍了如何使用分治法改进求解给定整数序列最大子列和的问题,从穷举法的O(N^3)到分而治之的O(NlogN),再到在线处理的O(N)效率提升。算法二和算法三是关键,通过递归和边界计算优化了重复计算。最后,算法四利用动态规划思想避免了负数子序列的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 给定N个整数的序列{ A1, A2, …, AN},其中可能有正数也可能有负数,找出其中连续的一个子数列(不允许空序列),使它们的和尽可能大,如果是负数,则返回0。使用下列函数,完成分治法求最大子列和。

算法一,穷举法T( N ) = O( N3 )

思想:算法思想:算出每个子序列的和,即算出序列中第i个到第j个数的和(j>=i),并进行比较

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( N2 )

对上一个算法的改进,减少重复计算

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 log N )

int MaxSum(int a[],int left,int right);

int threeOfMax(int a1,int a2,int a3);

int centerMaxSum(int a[],int left,int right);

#include<stdio.h>
#define N 50
int MaxSum(int a[],int left,int right);
int centerMaxSum(int a[],int left,int right);
int threeOfMax(int a1,int a2,int a3);
int main(){
 int n;
 int a[N];
    printf("请设置数组位数n:\n");
 scanf("%d",&n);
 printf("请输入数值:\n");
 for(int i = 0;i<n;i++){
  scanf("%d",&a[i]);
 }
 int left=0;
 int right=n-1; 
 int maxSubSum = MaxSum(a,left,right);
 printf("最大子序列的和为:%d\n",maxSubSum);
 return 0;
} 

int MaxSum(int a[],int left,int right){
 int a1,a2,a3,i;
 int MaxLeftSum, MaxRightSum; //存放左右子问题的解
    int MaxLeftBorderSum, MaxRightBorderSum; //存放跨分界线的结果

    int LeftBorderSum, RightBorderSum;
 // 递归终止条件 直到分到最后一个元素 
 if(left==right){
   if( a[left] > 0 )
            return a[left];
        else
            return 0;
 }
 int mid = (left+right)/2;
 // 划分左边
 a1 = MaxSum(a,left,mid);
 // 划分右边
 a2 = MaxSum(a,mid+1,right);
 // 求解s3 
    MaxLeftBorderSum = 0;
    LeftBorderSum = 0;
    for( i=mid; i>=left; i-- )   //从中线向左扫描
    {
        LeftBorderSum += a[i];
        if( LeftBorderSum > MaxLeftBorderSum )
            MaxLeftBorderSum = LeftBorderSum;
    } //左边扫描结束

    MaxRightBorderSum = 0;
    RightBorderSum = 0;
    for( i=mid+1; i<=right; i++ )   //从中线向右扫描
    {
        RightBorderSum += a[i];
        if( RightBorderSum > MaxRightBorderSum )
            MaxRightBorderSum = RightBorderSum;
    } //右边扫描结束 
    a3 =centerMaxSum(a,left,right);;
    //下面返回"治"的结果
    return threeOfMax( MaxLeftSum, MaxRightSum, MaxLeftBorderSum + MaxRightBorderSum );

}
// 求解s3 
int centerMaxSum(int a[],int left,int right){
 int leftSum = 0;
 int rightSum = 0;
    int templeftSum = 0;
 int temprightSum = 0;
 int mid=(left+right)/2;
 for(int i = mid;i>=left;i--){
  templeftSum = templeftSum+a[i];
  if(templeftSum>leftSum)
  leftSum=templeftSum; 
 }
 for(int j = mid+1;j<=right;j++){
  temprightSum = temprightSum+a[j];
  if(temprightSum>rightSum)
  rightSum=temprightSum;
 }
 
 return leftSum+rightSum;
}

// 求解最大的子列和 
int threeOfMax(int a1,int a2,int a3){
	int maxSum = a1>a2?a1:a2;
	return maxSum>a3?maxSum:a3;
}

算法四在线处理T( N ) = O( N)

设a[i]为和最大序列的起点,则如果a[i]是负的,那么它不可能代表最优序列的起点,因为任何包含a[i]作为起点的子序列都可以通过a[i+1]作起点而得到改进。

int MaxSubseqSum4( int A[], int N )
{ int ThisSum, MaxSum;
  int i;
  ThisSum = MaxSum = 0;
  for( i = 0; i < N; i++ ) {
    ThisSum += A[i]; /* 向右累加*/
    if( ThisSum > MaxSum )
      MaxSum = ThisSum; /* 发现更大和则更新当前结果*/
    else if( ThisSum < 0 ) /* 如果当前子列和为负*/
      ThisSum = 0; /* 则不可能使后面的部分和增大,抛弃之*/
  }
  return MaxSum;

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值