算法学习笔记:最大连续子数组

寻找最大连续子数组

  这两天看了看数据结构与算法,对其中一个问题颇感兴趣,所以在这里写一下。问题:寻找最大连续子数组。

  问题:在一个有正有负的数组中,寻找一个连续的、和最大的子数组。这个数组类似于下面的数组,否则这个问题没有意义(如果全是正数的话,所有数组元素的和一定是最大的,同样全为负数也没有意义。)。

  

 int a={1,-2,3,45,-78,34,-2,6};

解法一:暴力求解。

  那么如何来解决这个问题呢?这个思路要起来并不难,绝大多数人会想到这样的办法:遍历该数组的所有子数组,找到和最大的那个子数组即可。因为遍历一次需要O(N)这么多时间,而数组又有N个元素,所以这个方法所用的时间为O(N^2)。那么有没有更快一点的方法呢?有!

方法二:分治法。

  分治法的意思就是“分而治之”。该方法把原问题分解为规模较小的子问题(一般为等分),这些子问题性质与原问题相同但是规模较小,求解这些子问题后合并这些子问题的解便得到了原问题的解。

  

    我们将数组一分为二:分划左为A,分划右为B。那么一个数组的最大连续子数组这有三种可能:全在A,全在B,横跨在分划线的两端。寻找A与B的任务与原来的任务相同,先不理会,先去寻找横跨的那个子数组。

  

FIND_MAX_CROSSING_ARRAY(A,low,mid,high)
left-sum=-无穷
find_left=0;
sum=0
for i=mid downto low
    if (sum+a[i]>sum)
        left_sum=sum
        find_left=i
sum=0;
right_sum=-无穷
find_right=0;
for i=mid+1 to high
    if (sum+a[i]>sum)
         right_sum=sum
         find_right=i
sum=left_sum+right_sum
return sum,find_left,find_right

  以上就是寻找横跨最大连续子数组的伪代码。有了这个伪代码,我们就可以设计一个新的算法来寻找最大连续子数组。

 

FIND_MAX_ARRAY(A,low,high)
    if low==high
        return A[low],low,high
    else
        mid=(low+high)/2
        (left,left_low,left_high)=FIND_MAX_ARRAY(A,low,mid)
        (right,right_low,right_high)=FIND_MAX_ARRAY(A,mid+1,high)
        (mid1,mid_low,mid_high)=FIND_MAX_CROSSING_ARRAY(A,low,mid,high)
        //这样就分别找到了各自的最大连续子数组,找到三者最大返回即可
    比较三者,找到最大的那个。
    return (最大值,下标,上标)

  这就是寻找最大子数组的伪代码了,通过分析发现时间复杂度为O(nlogn)。在渐进效率上击败了平凡算法。这就是利用分治法解决最大连续子数组的伪代码。

方法三:类动态规划

  利用如下思维解决这个问题。

  D为后来新加入的元素,A为原数组的最大部分而B、C是被抛弃的区域,显然B与C的和都小于零,否则A便不是最大的区域。此时加入了D之后,最大的连续子数组存在于三个情况之中:A,A+C+D,D,不会再出现其它的情况。可以在常量时间内解决。所以这也是个办法是线性时间的。

  注意:在分治法中把数组一分为二可能遇到数组无法正好平分的情况,此时采取取整的策略。可以证明不会影响该算法的实施与时间复杂度。

 

 

 

 

     

 

转载于:https://www.cnblogs.com/wufeng1234/p/4562619.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值