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

例如对于输入:-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;imax)
           {
               max=thisSum;
           }
           //这时之前保存的最大子序列和仍然是存在的  分割  重新开始求和  再和之前的进行比较
           else if(thisSum<0)
           {
               thisSum=0;
           }
       }
       return max;
   }
}
此算法是线性的  它只对数据进行一次扫描,不需要存储数组的其他部分,不仅如此,在任意时刻算法都能对已经读出的数据给出子序列问题的正确答案(其他算法不具有这个特性)。具有这种特性的算法叫做联机算法。仅需要常量空间并且以线性时间运行的联机算法几乎是完美的算法。

你可能感兴趣的:(数据结构)