最大子段和问题的算法完整程序
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最大子段和问题的算法完整程序相关的知识,希望对你有一定的参考价值。
用分治法和动态规划法分别编写程序。并比较他们的区别。
/*简单算法:**v[0]不保存数据
**T(n)=O(n^2).
*/
int MaxSum(int *v,int n,int *besti,int *bestj)
int sum=0;
int i,j;
for (i=1;i<=n;i++)
int thissum=0;
for (j=i;j<=n;j++)
thissum+=v[j];
if (thissum>sum)
sum=thissum;
*besti=i;
*bestj=j;
return sum;
/*分治法:
**将a[1n]分成a[1n/2]和a[n/2+1n],则a[1n]的最大字段和有三种情况:
**(1)a[1n]的最大子段和与a[1n/2]的最大子段和相同
**(2)a[1n]的最大子段和与a[n/2n]的最大子段和相同
**(3)a[1n]的最大子段和为ai++aj,1<=i<=n/2,n/2+1<=j<=n
**T(n)=2T(n/2)+O(n)
**T(n)=O(nlogn)
*/
int MaxSum_DIV(int *v,int l,int r)
int k,sum=0;
if(l==r)
return v[l]>=0?v[l]:0;
else
int center=(l+r)/2;
int lsum=MaxSum_DIV(v,l,center);
int rsum=MaxSum_DIV(v,center+1,r);
int s1=0;
int lefts=0;
for (k=center;k>=l;k--)
lefts+=v[k];
if(lefts>s1)
s1=lefts;
int s2=0;
int rights=0;
for (k=center+1;k<=r;k++)
rights+=v[k];
if(rights>s2)
s2=rights;
sum=s1+s2;
if(sum<lsum)
sum=lsum;
if(sum<rsum)
sum=rsum;
return sum;
/*动态规划算法:
**b[j]=maxa[i]++a[j],1<=i<=j,且1<=j<=n,则所求的最大子段和为max b[j],1<=j<=n。
**由b[j]的定义可易知,当b[j-1]>0时b[j]=b[j-1]+a[j],否则b[j]=a[j]。故b[j]的动态规划递归式为:
**b[j]=max(b[j-1]+a[j],a[j]),1<=j<=n。
**T(n)=O(n)
*/
int MaxSum_DYN(int *v,int n)
int sum=0,b=0;
int i;
for (i=1;i<=n;i++)
if(b>0)
b+=v[i];
else
b=v[i];
if(b>sum)
sum=b;
return sum;
参考技术A 分治算法时间复杂度为N*log N,这个我就不帮你写了,我帮你写个动态规划时间复杂度为O(n),空间复杂度为O(1) ,int A[]即为要查找的数组
#include<stdio.h>
struct Tint nMaxSum,nFirst,nLast;;
T MaxSum(int A[],int first,int last);
int main()
int A[] = 10,-2,-2,3,4,5;
T t = MaxSum(A,0,sizeof(A) / sizeof(int) - 1);
printf("(%d,%d,%d)\n",t.nMaxSum,t.nFirst,t.nLast);
return 0;
T MaxSum(int A[],int first,int last)
T result = 0,0,0;
int nCurSum = A[first];
int nCurStart = first;
result.nMaxSum = A[first];
result.nFirst = first;
result.nLast = first;
for(int i = first + 1;i <= last;i++)
if(nCurSum <= 0)
nCurStart = i;
nCurSum = 0;
nCurSum += A[i];
if(nCurSum > result.nMaxSum)
result.nMaxSum = nCurSum;
result.nFirst = nCurStart;
result.nLast = i;
return result;
参考技术B 一维上的最大子段和问题,从左到右一遍扫描即可,没必要分治吧?也谈不上DP。
关于求最大子段和的几种算法
一、比较朴素的算法
算法思想:我们确定每个子段和开始的位置,分别为第一个,第二个,第三个......第N个,然后计算从这个位置开始到这个位置之后的每个位置的子段和,更新记录最大的子段和。
时间复杂度:O(n^2)
算法实现(Java):
package com.Third; import java.util.*; public class Main3{ public static int maxSum2(int a[]){ int nowSum=0;//用于记录从指定位置到当前位置累加的值 int maxSum=0;//用于记录当前最大的子段和 for(int i=0;i<a.length;i++){ nowSum=0; for(int j=i;j<a.length;j++){ nowSum=nowSum+a[j]; if(nowSum>maxSum){//更新最大子段和 maxSum=nowSum; } } } return maxSum; } public static void main(String[] args) { int a[]={4,-3,5,-2,-1,2,6,-2}; System.out.println(maxSum2(a)); } }
二、分治法(递归)
算法思想:
通过分治的思想求最大子段和,将数组分平均分为两个部分,则最大子段和会存在于三种情况下:
1.最大子段和出现在左端
2.最大子段和出现在右端
3.最大子段和横跨在左右段 通过比较大小得到最大子段和
时间复杂度:O(nlogn)
算法实现(Java):
package com.Third; /* * 通过分治的思想求最大子段和,将数组分平均分为两个部分,则最大子段和会存在于三种情况下: * 1.最大子段和出现在左端 * 2.最大子段和出现在右端 * 3.最大子段和横跨在左右段 */ public class Main { public static int maxSumRec(int []a,int start,int end){ if(start==end){//这里是递归的函数出口 if(a[start]>0){ return a[start]; }else{ return 0; } } int maxLeftSumRec=maxSumRec(a,start,(start+end)/2);//计算左半边的最大字段和 int maxRightSumRec=maxSumRec(a,((start+end)/2)+1,end);//计算右半边最大子段和 //计算最大子段和在中间的情况 int leftMaxMark=0; int leftSum=0; for(int i=(start+end)/2;i>=0;i--){ leftSum=leftSum+a[i]; if(leftSum>leftMaxMark){ leftMaxMark=leftSum; } } int rightMaxMark=0; int rightSum=0; for(int i=((start+end)/2)+1;i<=end;i++){ rightSum=rightSum+a[i]; if(rightSum>rightMaxMark){ rightMaxMark=rightSum; } } int maxMidSumRec=leftMaxMark+rightMaxMark; //比较三种情况那种情况是最大的子段和 int maxSum=maxLeftSumRec; if(maxSum<maxRightSumRec){ maxSum=maxRightSumRec; } if(maxMidSumRec>maxSum){ maxSum=maxMidSumRec; } return maxSum; } public static void main(String[] args) { int a[]={4,-3,5,-2,-1,2,6,-2}; System.out.println(maxSumRec(a,0,7)); } }
三、动态规划算法
算法思想:
运用了动态规划的思想来解决最大子段和问题:
通过遍历累加这个数组元素,定时的更新最大子段和,
如果当前累加数为负数,直接舍弃,重置为0,然后接着遍历累加。
时间复杂度:O(n)
算法实现(Java):
package com.Third; /* * 这是运用了动态规划的思想来解决最大子段和问题: * 通过遍历累加这个数组元素,定时的更新最大子段和, * 如果当前累加数为负数,直接舍弃,重置为0,然后接着遍历累加。 */ public class Main1{ public static int maxSubSum1(int []a){ int maxSum=0; int nowSum=0; for(int i=0;i<a.length;i++){ nowSum=nowSum+a[i]; if(nowSum>maxSum){//更新最大子段和 maxSum=nowSum; } if(nowSum<0){//当当前累加和为负数时舍弃,重置为0 nowSum=0; } } return maxSum; } public static void main(String[] args) { int a[]={4,-3,5,-2,-1,2,6,-2}; System.out.println(maxSubSum1(a)); } }
以上是关于最大子段和问题的算法完整程序的主要内容,如果未能解决你的问题,请参考以下文章
算法竞赛进阶指南扩展最大子段和POJ1050ToTheMax