数据结构--最大子序列和(使用分治策略和递归)

来源:互联网 发布:excel vba 定义数组 编辑:程序博客网 时间:2024/06/10 08:06

例如对于输入:-2,11,-4,13,-5,-2答案为20   为方便起见 若所有整数为负数 则最大子序列和为0

算法一:

分治策略:其想法是把问题分成大致相等的子问题,然后递归的对他们求解,这是“分”的部分,“治”是将两个子问题的解修不到一起并作少量附加工作,最后得到整个问题的解。

对于这个问题,可以分为三个部分,一个是最大子序列可能出现在输入数据的左半部分,第二种是出现在数据的右半部分,还有一种是在中间。第三部分可以通过求出前半部分的最大和(包括前半部分最后一个元素)和后半部分的最大和(包括后半部分的第一个元素),把这两个和相加就是中间部分的最大和,三个最大再比较下即可。

package com.itany.zuidazixulie;public class Test{   public static void main(String[] args)   {       int[] nums={2,-1,4,7,-6,5,8,-2};       System.out.println("最大子序列和是:"+ maxSumRec(nums,0,nums.length-1));   }   // 2 -1 4 7 | -6 9 8 -2 只对个数为2的N次方个数使用   public static int maxSumRec(int[] nums,int left,int right)   {       //基准情况 即只有一个数的情况       if(left==right)       {           if(nums[left]>0)               return nums[left];           else               return 0;       }       int center=left+(right-left)/2;       int maxLeft=maxSumRec(nums,left,center);       int maxRight=maxSumRec(nums,center+1,right);       int maxLeftBorder=0,leftBorder=0;       int maxRightBorder=0,rightBorder=0;       for(int i=center;i>=left;i--)       {           leftBorder+=nums[i];           //此处必须包含边界 所以通过一直相加  如果>最大的和  则还有最大子序列           if(leftBorder>maxLeftBorder)               maxLeftBorder=leftBorder;       }       for(int i=center+1;i<=right;i++)       {           rightBorder+=nums[i];//此处必须包含边界 所以通过一直相加  如果>最大的和  则还有最大子序列           if(rightBorder>maxRightBorder)               maxRightBorder=rightBorder;       }       return maxOfThree(maxLeft,maxRight,(maxLeftBorder+maxRightBorder));   }   //计算三部分中的最大值   public static int maxOfThree(int maxLeft,int maxRight,int center)   {       int max=maxLeft;       if(maxRight>max)       {           max=maxRight;           if(center>max)               max=center;       }       return max;   }}

算法二:

package com.itany.zuidazixulie;public class Test2{   public static void main(String[] args)   {       int[] nums={2,-1,4,7,-69,5,8,-2};       System.out.println("最大子序列和是:"+ maxSumRec(nums));   }   public static int maxSumRec(int[] nums)   {       int max=0;       int thisSum=0;       for(int i=0;i<nums.length;i++)       {           thisSum+=nums[i];           if(thisSum>max)           {               max=thisSum;           }           //这时之前保存的最大子序列和仍然是存在的  分割  重新开始求和  再和之前的进行比较           else if(thisSum<0)           {               thisSum=0;           }       }       return max;   }}
此算法是线性的  它只对数据进行一次扫描,不需要存储数组的其他部分,不仅如此,在任意时刻算法都能对已经读出的数据给出子序列问题的正确答案(其他算法不具有这个特性)。具有这种特性的算法叫做联机算法。仅需要常量空间并且以线性时间运行的联机算法几乎是完美的算法。

0 0
原创粉丝点击