最大连续子序列和:动态规划经典题目

【题目】

给定k个整数的序列{N1,N2,…,Nk },其任意连续子序列可表示为{ Ni, Ni+1, …, Nj },其中 1 <= i <= j <= k。最大连续子序列是所有连续子序中元素和最大的一个,例如给定序列{ -2, 11, -4, 13, -5, -2 },其最大连续子序列为{11,-4,13},最大连续子序列和即为20。

【注】:为方便起见,如果所有整数均为负数,则最大子序列和为0。

解决这样一个问题是一个很有趣的过程,我们可以尝试着从复杂度比较高的算法一步一步地推出复杂度较低的算法。

【算法1】

时间复杂度:O(N^3)

int MaxSubSequence(const int A[], int N){  
  int ThisSum,MaxSum,i,j,k;  
  MaxSum = 0;  
  for(i=0;i<N;i++)
  {  
    for(j=i;j<N;j++)  
    {  
      ThisSum = 0;  
      for(k=i;k<=j;k++)  
      {  
        ThisSum += A[k];  
      }  
      if(ThisSum > MaxSum)  
        MaxSum = ThisSum;  
    }  
  }  
  return MaxSum;  
}  

【算法2】

时间复杂度 O(N^2)

int MaxSubSequence(const int A[], int N){  
  int ThisSum,MaxSum,i,j;  
  MaxSum = 0;  
  for(i=0;i<N;i++)  
  {  
    ThisSum = 0;  
    for(j=i;j<N;j++)  
    {  
      ThisSum += A[j];  
      if(ThisSum > MaxSum)  
        MaxSum = ThisSum;  
    }  
  }  
  return MaxSum;  
}  

【算法3:递归法(分治法)】

时间复杂度:O(NlogN)

    易知,对于一数字序列,其最大连续子序列和对应的子序列可能出现在三个地方。或是整个出现在输入数据的前半部(左),或是整个出现在输入数据的后半部(右),或是跨越输入数据的中部从而占据左右两半部分。前两种情况可以通过递归求解,第三种情况可以通过求出前半部分的最大和(包含前半部分的最后一个元素)以及后半部分的最大和(包含后半部分的第一个元素)而得到,然后将这两个和加在一起即可。
int MaxSubSequence(const int A[],int N)  
{  
  return MaxSubSum(A,0,N-1);  
}  

static int MaxSubSum(const int A[], int Left, int Right)  
{  
  int MaxLeftSum,MaxRightSum;  
  int MaxLeftBorderSum,MaxRightBorderSum;  
  int LeftBorderSum,RightBorderSum;  
  int Center,i;  

  if(Left == Right)  
  {  
    if(A[Left] > 0)  
      return A[Left];  
    else  
      return 0;  
  }  

  Center = (Left + Right)/2;  
  MaxLeftSum = MaxSubSequence(A,Left,Center);  
  MaxRightSum = MaxSubSequence(A,Center+1,Right);  

  MaxLeftBorderSum = 0;  
  LeftBorderSum = 0;  
  for(i = Center;i >= Left;i--)  
  {  
    LeftBorderSum += A[i];  
    if(LeftBorderSum > MaxLeftBorderSum)  
      MaxLeftBorderSum = LeftBorderSum;  
  }  

  MaxRightBorderSum = 0;  
  RightBorderSum = 0;  
  for(i = Center+1;i <= Right;i++)  
  {  
    RightBorderSum += A[i];  
    if(RightBorderSum > MaxRightBorderSum)  
      MaxRightBorderSum = RightBorderSum;  
  }   

  return Max(MaxLeftSum,MaxRightSum,MaxLeftBorderSum + MaxRightBorderSum);  
}   

int Max(int a, int b, int c)  
{  
  if(a>b&&a>c)  
    return a;  
  else if(b>a&&b>c)  
    return b;  
  else  
    return c;   
}  

【算法四:动态规划法】

时间复杂度:O(N)

int MaxSubSequence(const int A[], int N)  
{  
  int ThisSum,MaxSum,j;  
  ThisSum = MaxSum =0;  
  for(j = 0;j < N;j++)  
  {  
    ThisSum += A[j];  

    if(ThisSum > MaxSum)  
      MaxSum = ThisSum;  
    else if(ThisSum < 0)  
      ThisSum = 0;   
  }  
  return MaxSum;   
}  

博客内容转自最大连续子序列和:动态规划经典题目

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值