最大子序列

一 问题描述:

输入一组整数,求出这组数字子序列和中最大值。也就是只要求出最大子序列的和,不必求出最大的那个序列。例如:

序列:-3 18 -4 5 -5 -2,则最大子序列和为23。

二 解法1:穷举解法

 1 int maxsequence(int a[],int len){
 2   int maxsum = 0;
 3   for(int i = 0;i < len;i++){
 4     for(int j = i;j<len;j++){
 5       int newsum = 0;
 6       for(int k = i;k <=j;k++){
 7         newsum+=a[k];
 8       }   
 9       if(newsum > maxsum)
10         maxsum = newsum;
11     }   
12   }
13   return maxsum;
14 }

     这个算法本身是非常简单和容易理解的,通过三个for循环直接给出所有可能出现的子序列,从中选出一个最大值即可。但是该方法时间复杂度真的是太大了,达到了O(n3)有很多操作完成是重复性的操作。例如当i = 0时,j = 1 时:该算法会计算a[0]+a[1],而当i = 0,j = 2时候,该算法会计算a[0]+a[1]+a[2],显然a[0]+a[1] 被重复计算了。

三 解法2:穷举解法2

 1 int maxsequence2(int a[],int len){
 2   int maxsum = 0;
 3   for(int i = 0;i < len;i++){
 4     int newsum = 0;
 5     for(int j = i;j<len;j++){
 6       newsum+=a[j];
 7       if(newsum > maxsum)
 8         maxsum = newsum;
 9     }   
10   }
11   return maxsum;
12 }

这个算法本身其实也是非常容易理解的,它不过是上面那个解法的改进,当我们计算i..j的值时候,i--j-1已经被计算过了,可以直接利用,不用重新计算一次i..j-1。其时间复杂度为O(n2),当然了,很明显的,这个时间复杂度也还是非常高的,在计算机里面,一个算法复杂度达到O(n2)其实还是一件比较可怕的事情。

四 解法3:分治法

int max3(int i, int j, int k)
{
  if (i>=j && i>=k)
    return i;
  else if(j >= i && j >= k)
    return j;
  else
    return k;
}

int max_seq(int a[],int left,int right)
{
  if(left > right)
    return 0;
  if(left == right)
    return a[left];

  int mid = (left + right)/2;

  int lmax=a[mid], lsum = 0;
  for(int i = mid;i >=left;i--){
    lsum += a[i];
    if (lsum > lmax)
      lmax = lsum;
  }

  int rmax = a[mid+1];
  int rsum = 0;

for(int i = mid+1;i<=right;i++){ rsum += a[i]; if(rsum > rmax) rmax = rsum; } return max3(lmax+rmax,max_seq(a,left,mid),max_seq(a,mid+1,right)); } int maxsequence3(int a[],int len){ return max_seq(a,0,len-1); }

这个算法的核心就是分治思想。我们假设将我的已经知道的序列分成左右两部分,那么最大子序列存在的位置显然有三种可能:

  (1)  存在在序列的左部

  (2)  存在在序列的右部

  (3)  既存在在序列的左部又存在在序列的右部。

显然如果是情况(3),是比较容易算出来的。如果是情况(1)和 (2)的话,我们可以将左部和右部当中一个重新的序列计算,那么新的序列又可以分成左右部分,重复以上即可。该算法的时间复杂度了O(n * lg(n))。

五 解法四:动态规划

int maxsequence4(int a[],int len){

  int maxsum = a[0];
  int maxnew = a[0];
  for(int i = 1;i < len;i++){
    if(maxnew <= 0)
      maxnew = a[i];
    else
      maxnew += a[i];

    if(maxnew > maxsum)
      maxsum = maxnew;
  }
  return maxsum;
}

该算法的时间复杂度显然就是O(n),对于计算机来说当然是非常友好的一件事情了,当是对于人来说就不是那么友好了(当然了,神人除外)。我们可以想一下,最大的子序列有什么特点呢?那就是其前m个元素之和也一定不能小于0,为什么?我们假设序列a的长度为len,假设a[i].....a[j],表示为a的最大子序列。如果sum[i->i+m]< 0,那么sum[i+m+1->j] > sum[i->j],矛盾。

代码体现:

    if(maxnew <= 0)
      maxnew = a[i];
原文地址:https://www.cnblogs.com/bspp1314/p/9369029.html