最大子序列问题(转)

做acm遇到这个问题不会,特地查找了一下相关的方法,在看到的方法中本文的第3个方法的代码思路清晰,相对于分治法虽然复杂度略高,但是有代码更简单更易写的优势,特此转载保存以便以后回顾。(原文链接在最下方)

问题描述:
给定整数(可以为负数),A1,A2,A3,…,AN,求子序列最大的值
举例:
对于整数列-1,11,-4,13,-5,-2, 最大的序列值为20 子序列为(11,-4,13)
算法1(楼主首先想到的办法,时间复杂度为:O(n2)):
解析:遍历此序列,取得每个小子序列的值,比较,最后得到最大的序列值,生成以下子序列并取得所有子序列和

-1

-1,11

-1,11,-4,13,-5,-2

11

11,-4

11,-4,13,-5,-2


实现:
public static int maxSubSum2(int [] iargs){ int sum=0; for(int i=0;i<iargs.length;i++){ int thissum=0; for(int j=i;j<iargs.length;j++){ thissum+=iargs[j]; if(thissum>sum){ sum=thissum; } } } return sum; }
算法2(算是小大招,时间复杂度为O(nlogn)):
解析:在我们例子中,最大的子序列可能存在三个部分,(左边部分、右边部分、左边一部分+右边一部分),如下表所示:

左边部分
右边部分

-1,11,-4
13,-5,-2

左边部分最大子序列为:11,右边部分最大子序列为13,左边+右边最大子序列为20,(11,-4,13)
实现:
public static int maxSubSum3(int[] a,int left,int right){ int sum=0; if(left==right){ sum=a[left]>0?a[left]:0; return sum; } int center=(left+right)/2; int leftMax=maxSubSum3(a,left,center); int rightMax=maxSubSum3(a,center+1,right); int maxLeftBorder=0,leftBorderSum=0; for(int i=center;i>=left;i–){ leftBorderSum+=a[i]; if(maxLeftBorder<leftBorderSum){ maxLeftBorder=leftBorderSum; } } int maxRightBorder=0,rightBordeSumr=0; for(int i=center+1;i<=right;i++){ rightBordeSumr+=a[i]; if(maxRightBorder<rightBordeSumr){ maxRightBorder=rightBordeSumr; } } return max3(leftMax,rightMax,maxLeftBorder+maxRightBorder); } public static int max3(int a,int b,int c){ int cen=a>b?a:b; return c>cen?c:cen; }
算法3(大招,时间复杂度为O(n),不看源码想不到,修炼不够啊):
解析:

假设a[i]为负数,则a[i]不可能为此子序列的起始,同理,若a[i]到a[j]的子序列为负,则a[i]到a[j]不可能为子序列的起始,则可以从a[j+1]开始推进,

实现:
public static int maxSubSum4(int a[]){ int thisMax=0,maxSum=0; for(int i=0;i<a.length;i++){ thisMax+=a[i]; if(thisMax>maxSum){ maxSum=thisMax; } if(thisMax<0){ thisMax=0; } } return maxSum; }

算法三 只对数据进行一次扫描,一旦a[i]被读入并处理,它就不再需要被记忆。因此数组可以被按顺序读入,在主存中不必存储数组的任何部分。具有这种特性的算法叫联机算法(on-line algorithm),仅需要常量空间并以线性时间运行的联机算法几乎是完美算法!

以下为python版实现
def maxSubSum1(*a): max=0 for i,value in enumerate(a): thisMax=0 for j in a[i:]: thisMax+=j if thisMax>max : max=thisMax return max def maxSubSum2(left,right,*a): if left==right: #base case return a[left] center =(left+right)/2 maxLeft=maxSubSum2(left,center,*a) maxRight=maxSubSum2(center+1,right,*a) leftSum=0 maxLeftSum=0 i=center while i>=0: leftSum+=a[i] if leftSum>maxLeftSum: maxLeftSum=leftSum i=i-1 rightSum = 0 maxRightSum = 0 i = center+1 while i <=right : rightSum += a[i] if rightSum > maxRightSum: maxRightSum = rightSum i = i + 1 return max(maxLeft,maxRight,maxLeftSum+maxRightSum) def max(*a): max=0 for i in a: if i>max: max=i return max def maxSubSum3(*a): max=0 thisMax=0 for i in a: thisMax+=i if thisMax>max: max=thisMax if thisMax<0: thisMax=0 return max

作者:limiracle
链接:https://www.jianshu.com/p/20afa593c4d3
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

猜你喜欢

转载自blog.csdn.net/weixin_43305764/article/details/84939849
今日推荐