数据结构—分治法小结

来源:互联网 发布:linux运维入门 编辑:程序博客网 时间:2024/05/16 08:36

分治由两部分组成。

分:递归地求解更小的问题。

治:子问题的解决方案形成了原问题的解决方案。

原则上,至少包含两个递归调用的算法才是分治法。子问题之间通常是不相交的。因此FIB数列不属于分治法。


最大连续子序列。

最大连续子序列采用分治法思考,将输入一分为2,存在三种情况

1完全在左边

2完全在右边

3一部分在左边,一部分在右边

针对情况三我们考虑使用两个for循环分别寻找前后两部分的最大值,因为如果最大数组分布在左右两侧的话,必定包含从分界点向左和向右的部分数组,且这部分数组是最大值,否则,数组可以包含的更长。(注意,这里计算左侧的数组是从center开始到head的最大连续子序列,右侧的数组是从center+1到tail的最大连续子序列,这里计算的时候是对所有数进行累加,并不存在跳跃的问题,因为构成的最长序列必须连续,如果左右不连续了,就错了)

例如4 -3 5 -2 -1 2 6 -2

前半部分后半部分4 -3 5 -2-1 2 6 -24 0 3 -2-1 1 7 5其中4是最大的,左侧包含所有的序列

其中7是最大的,右侧包含到6为止的序列

最长子序列为4 -3 5 -2 -1 2 6 -2

和为4+7=11

对以情况一和情况三使用同样的策略,依次进行减半,我们可以一直进行分割到不能分割为止。

即 1递归计算前半部分最大连续子序列和 2递归计算后半部分最大连续子序列和 3是应用两个连续循环计算同时包含在前半部分和后半部分的最大连续子序列的和 4选择最大的一个。递归出口为规模达到1个元素时,便不再递归。

代码:

public static int maxSumRec(int[] a,int left,int right){    if(left==right)return a[left];    int leftMax=0,rightMax=0;//左侧右侧最大序列(用来计算第三种情况)    int leftSum=0,rightSum=0;//左侧右侧序列和(用来计算第三种情况)    int center = (left+right)/2;    int maxleft = maxSumRec(a,left,center);//递归计算左侧的最大子序列    int maxright = maxSumRec(a,center+1,right);//递归计算右侧的最大子序列    //计算第三种情况    for(int i=center;i>=left;i--){        leftSum+=a[i];        if(leftSum>leftMax)leftMax=leftSum;    }    for(int i=center+1;i<=right;i++){        rightSum+=a[i];        if(rightSum>rightMax)rightMax=rightSum;    }    return Math.max(Math.max(maxleft,maxright),leftMax+rightMax);//返回左侧,右侧,两侧最大值}
执行流程

最大连续子序列-分治算法时间复杂度分析


分治算法时间复杂度的一般上界-主要分为3种情况:


原创粉丝点击