分治策略 最大子数组问题
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)归并排序的递归式一样
以上是关于分治策略 最大子数组问题的主要内容,如果未能解决你的问题,请参考以下文章