对于公共子序列和的求法,我们在学习算法的时候都知道基本的有四种,他们的时间复杂度分别为:O(N^3) / O(N^2) / O(N logN) / O(N) ,对于前面的两种都是for循环的嵌套,时间用的太多,很不实用,这里就不再写了。只写后面的两种,就当是练手了~
第一种: 递归法(分治)
把现有的子序列分两段,那么它的最长子序列和的产生只能发生于三种情况: (1)在左半部分产生;(2)在右半部分产生;(3)两半部分的和相加得到 。 如 1 -4 3 -1 2 6 -3 4,分段后左边的最大和为:3,右边的最大和为:9,此时他们的整体最大和就由两部分的和构成,为11。
代码:
private static int maxSumRec(int [] a,int left,int right) { if(left==right) // 在临界点时,如果数组中的值是小于0的,直接舍掉,如果是正值就直接加上; if(a[left]>0) return a[left]; else return 0; // 在没有到达基点是做下面的递归运算; // 对两边分别做的递归处理; int center=(right+left)/2; int maxLeftSum=maxSumRec(a,left,center); // 开始进入递归运算; int maxRightSum=maxSumRec(a,center+1,right); // 对左右两边和的最大值的处理; int maxLeftBorderSum=0,leftBorderSum=0; for(int i=center;i>=left;i--) // 从中间向左一直做加运算,求得包含中间左端向左的最大和子序列的和; { leftBorderSum+=a[i]; if(leftBorderSum>maxLeftBorderSum) maxLeftBorderSum=leftBorderSum; } int maxRightBorderSum=0,rightBorderSum=0; for(int i=center+1;i<=right;i++) { rightBorderSum+=a[i]; if(rightBorderSum>maxRightBorderSum) maxRightBorderSum=rightBorderSum; } return max3(maxLeftSum,maxRightSum,maxLeftBorderSum+maxRightSum); } public static int maxSubSum3(int []a) { return maxSumRec(a,0,a.length-1); } public static int max3(int a,int b,int c) { return a>(b>c?b:c)?a:(b>c?b:c); // 返回三个数中最大的那个; }
第二种: 动态规划法
代码: 局部最优解构成整体最优解;
public static int maxSumRec(int []a) { int maxSum=0,thisSum=0; // maxSum 是要求的最大公共子序列的值;thisSum 是当前得到的序列的和; for(int j=0;j<a.length;j++) { thisSum+=a[j]; // 对当前的thisSum更新; if(thisSum>maxSum) maxSum=thisSum; //对当前的maxSum更新; else if(thisSum<0) thisSum=0; } return maxSum; }
上面的只是本人的学习笔记,错误不可避免,欢迎大家指正!