求解最大子段和问题----分治 蛮力 dp

【问题描述】给定一个有n(n≥1)个整数的序列,要求求出其中最大连续子序列的和。
例如:
序列(-2,11,-4,13,-5,-2)的最大子序列和为20
序列(-6,2,4,-7,5,3,2,-1,6,-9,10,-2)
的最大子序列和为16。
规定一个序列最大子段和至少是0,如果小于0,其结果为0。
蛮力法
穷举所有连续子序列来得到。
设含有n个整数的序列a[0…n-1],穷举所有的连续子序列a[i…j],求出它的所有元素之和thisSum,并通过比较将最大值存放在maxSum中,最后返回maxSum。
在这里插入图片描述

long maxSubSum1(int a[],int n)
{       int i,j,k;
  long maxSum=a[0],thisSum; 
  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;
}

在这里插入图片描述
改进的蛮力法

long maxSubSum2(int a[],int n)
{      int i,j;
  long maxSum=a[0],thisSum;
  for (i=0;i<n;i++)                 // i是子列左端位置
  {     thisSum=0;                // thisSum是从a[i]到a[j]的子列和
    for (j=i;j<n;j++)          // j是子列右端位置
    {      thisSum+=a[j];
       if (thisSum>maxSum)
        maxSum=thisSum;
    }
  }
  return maxSum;
}

在这里插入图片描述
分治法

long maxSubSum3(int a[]int left,int right) 
//求a[left..right]序列中最大子段和
{  int i,j;
   long maxLeftSum,maxRightSum;
   long maxLeftBorderSum,leftBorderSum;
   long maxRightBorderSum,rightBorderSum;
   if (left==right)  //子序列只有一个元素时
   {  if (a[left]>0)  //该元素大于0时返回它
      return a[left];
    else   //该元素小于或等于0时返回0
       return 0; 
   } 
  int mid=(left+right)/2;   //求中间位置
  maxLeftSum=maxSubSum3(a,left,mid); //求左边
  maxRightSum=maxSubSum3(a,mid+1,right); //求右边
  maxLeftBorderSum=0,leftBorderSum=0;
  for (i=mid;i>=left;i--)    //求出以左边加上a[mid]元素
  {  leftBorderSum+=a[i];    //构成的序列的最大和
        if (leftBorderSum>maxLeftBorderSum)
      maxLeftBorderSum=leftBorderSum;
  }
  maxRightBorderSum=0,rightBorderSum=0;
  for (j=mid+1;j<=right;j++)  //求出a[mid]右边元素
  {  rightBorderSum+=a[j];    //构成的序列的最大和
     if (rightBorderSum>maxRightBorderSum)
      maxRightBorderSum=rightBorderSum;
  }
  return max3(maxLeftSum,maxRightSum,
     maxLeftBorderSum+maxRightBorderSum); 
} 

在这里插入图片描述
最优算法(就遍历一次)
从头开始扫描数组a,用sum(初值为0)记录当前子序列之和,用max(初值为0)记录最大连续子序列和。
如果扫描中遇到负数,当前子序列和sum将会减小,若sum为负数,表明前面已经扫描的那个子序列可以抛弃了,则放弃这个子序列,重新开始下一个子序列的分析,并置sum为0。
若这个子序列和sum不断增加,那么最大子序列和max也不断增加。

int maxSubSum4(int a[],int n)
{  int i,max=0,sum=0;
  for (i=0;i<n;i++)
  {  sum+=a[i];//向右累加
    if (sum<0) //若当前子序列和为负数,重新开始下一子序列
      sum=0;
    if (sum>max)//发现更大和则更新当前结果
      max=sum;
  }
  return max;
}

在这里插入图片描述
类似动态规划

发布了19 篇原创文章 · 获赞 2 · 访问量 737

猜你喜欢

转载自blog.csdn.net/qq_45639157/article/details/105078628