分治策略   最大子数组问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分治策略   最大子数组问题相关的知识,希望对你有一定的参考价值。


  递归式

  递归式与分治方法是紧密相关的,因为使用递归式可以很自然地刻画分治算法的运行时间。一个递归式就是一个等式或不等式,它通过更小的输入上的函数值来描述一个函数。例如,在2.3.2节,我们用递归式描述了MERGE-SORT过程的最坏情况运行时间T(n):

        Θ(1)        若n=1

T(n) =                         (4.1)

        2T(n/2)+Θ(n)    若n>1

求解可得T(n)=Θ(nlgn)

  递归式可以有很多形式。例如,一个递归算法可能将问题划分为规模不等的子问题,如2/3对1/3的划分。如果分解和合并步骤都是线性时间的,这样的算法会产生递归式T(n)=T(2n/3)+T(n/3)+Θ(n).

  子问题的规模不必是原问题规模的一个固定比例。例如,线性查找的递归版本仅生产一个子问题,其问题仅比原问题的规模少一个元素。每次递归调用将花费常量时间再加上上下一层递归调用的时间,因此递归式为T(n)=T(n-1)+Θ(n).

  本章介绍三种求解递归式的方法,即得出算法的"Θ"或"O"渐近界的方法:

  *代入法  我们猜测一个界,然后用数学归纳法证明这个界是正确的

  *递归树法 将递归式转换为一棵树,其节点表示不同层次的递归调用产生的代价。然后采用边界和技术来求解递归式

  *主方法  可求解形如下面公式的递归式的界:

                T(n) = aT(n/b) + f(n)

         其中a>=1,b>1,f(n)是一个给定的函数。这种形式的递归式很常见,它刻画了这样一个分          治算法:生成a个子问题,每个子问题的规模是原问题规模的1/b,分解和合并步骤总共花          费时间为f(n).

  

  我们偶尔会遇到不是等式而是不等式的递归式,例如T(n)<=2T(n/2)+Θ(n).因为这样一种递归式仅描述了T(n)的一个上界,因此可以用大O符号而不是Θ符号来描述其解。


  递归式技术细节

 在实际应用中,我们会忽略递归式声明和求解的一些技术细节。例如,如果对n个元素调用MERGE-SORT,当n为奇数时,两个子问题的规模分别为n/2下界和n/2上界,准确来说都不是n/2,因为当n是奇数时,n/2不是一个整数。


  当声明,求解递归式时,我们常常忽略向下取整,向上取整即边界条件。我们先忽略这些细节,然后再确定这些细节对结果是否有较大影响。通常影响不大,但你需要知道什么时候会影响不大。这一方面可以依靠经验来判断,另一方面,一些定理也表明,对于很多刻画分治算法的递归式,这些细节不会影响其渐近界。


FIND-MAX-CROSSING-SUBARRAY(A,low,mid,high)

1   left-sum = -∞

2   sum = 0

3   for i = mid downto low

4     sum = sum +A[i]

5     if sum > left-sums

6       left-sum = sum

7       max-left = i

8   right-sum = -∞

9   sum = 0

10  for j = mid +1 to high

11    sum = sum + A[j]

12    if sum > right-sum

13      right-sum = sum

14      max-right = j

15  return (max-left,max-right,left-sum + right-sum)


  此过程的工作方式如下所述。第1-7行求出左半部A[low..mid]的最大子数组。由于此数组必须包含A[mid],第3-7行的for循环的循环变量i是从mid开始,递减直至达到low,因此,它所考察的每个子数组都具有A[i..mid]的形式。第1-2行初始化变量left-sum和sum,前者保存目前为止找到的最大和,后者保存A[i..mid]中所有值的和。每当第5行找到一个子数组A[i..mid]的和大于left-sum时,我们在第6行将left-sum更新为这个子数组的和,并在第7行更新变量max-left来记录当前下标i.第8-14求右半部A[mid_1..high]的最大子数组,过程与左半部类似。此处,第10-14行的for循环的循环变量j是从mid+1开始,递增直至达到high,因此,它所考察的每个子数组都具有A[mid+1..j]的形式。最后,第15行返回下标max-left和max-right,划定跨越中点的最大子数组的边界,并返回子数组A[max-left..max-right]的和left-sum + right-sum

  如果子数组A[low..high]包含n个元素(即 n = high-low+1),则调用FIND-MAX-CROSSING-SUBARRAY(A,low,mid,high)花费Θ(1)时间,我们只需统计一共执行了多少次迭代。第3-7行的for循环执行了mid-low+1次迭代,第10-14行的for循环执行了high-mid次迭代,因此总循环次数为

    (mid-low+1)+(high-mid)=high-low+1=n

  有了一个线性时间的FIND-MAX-CROSSING-SUBARRAY在手,我们就可以设计求解最大子数组问题的分治算法的伪代码了:


FIND-MAXIMUM-SUBARRAY(A,low,high)

1   if high == low

2     return (low,high,A[low])        //base case:only one element

3   else mid=╘ (low+high)/2 ╛

4      (left-low,left-high,left-sum) = 

          FIND-MAXMUM-SUBARRAY(A,low,mid)

5      (right-low,right-high,right-sum) =

        FIND-MAXMUM-SUBARRAY(A,mid+1,high)

6       (cross-low,cross-high,cross-sum) = 

        FIND-MAXMUM-SUBARRAY(A,low,mid,high)

7       if left-sum>=right-sum and left-sum>=cross-sum

8         return (left-low,left-high,left-sum)

9     elseif right-sum>=left-sum and right-sum >= cross-sum

10        return (right-low,right-high,right-sum)

11      else retun (cross-low,cross-high,cross-sum)

初始调用FIND-MAXMUM-SUBARRAY(A,1,A.length)会求出A[1..n]的最大子数组。


分治算法的分析


假设原问题的规模为2的幂,这样所有子问题的规模均为整数。我们用T(n)表示FIND-MAXMUM-SUBARRAY求解n个元素的最大子数组的运行时间。首先,第1行花费常量时间。对于n=1的基本情况,也很简单:第2行花费常量时间,因此,

            T(1) = Θ(1)        (4.5)

  当n>1时为递归情况。第1行和第3行花费常量时间。第4行和第5行求解的子问题均为n/2个元素的子数组(假定原问题规模为2的幂,保证了n/2为整数),因此每个问题的求解时间为T(n/2).因为我们需要求解两个子问题---左子数组和右子数组,因此第4行和第5行给总运行时间增加了2T(n/2).而我们前面已经看到,第6行调用FIND-CROSSING-SUBARRAY花费Θ(n)时间,第7-11行仅花费Θ(1)时间。因此,对于递归情况,我们有

        T(n)=Θ(1)+2T(n/2)+Θ(n)+Θ(1)=2T(n/2)+Θ(n)    (4.6)

组合式(4.5)和式(4.6),我们得到FIND-MAXMUM-SUBARRAY运行时间T(n)的递归式:

            Θ(1)        若 n=1

T(n) =                             (4.7)

            2T(n/2)+Θ(n)    若n>1

此递归式与式(4.1)归并排序的递归式一样



以上是关于分治策略   最大子数组问题的主要内容,如果未能解决你的问题,请参考以下文章

分治策略   最大子数组问题

最大子数组问题的几种解法

分治算法 ------最大子段和

分治法解决最大子数组问题

算法导论最大子数组

算法题|-分治法解决最大子数组问题