求解递归式-主方法

分治策略递归式时间复杂度的求解方法主要有三种:代入法、递归树和主方法。其中主方法为求解递归式 T ( n ) = a T ( n / b ) + f ( n ) T(n)=aT(n/b)+f(n) T(n)=aT(n/b)+f(n)提供了一种“菜谱”式的求解方法。

公式: T ( n ) = a T ( n / b ) + f ( n ) T(n)=aT(n/b)+f(n) T(n)=aT(n/b)+f(n)

其中 a ≥ 1 a\ge1 a1 b > 1 b>1 b>1是常数, f ( n ) f(n) f(n)是渐近正函数。
递归式描述了这样一种算法的运行时间:它将规模为 n n n的问题分解成 a a a个子问题,每个子问题的规模是 n / b n/b n/b,其中 a a a b b b都是正常数。 a a a个子问题递归地进行求解,每个花费时间 T ( n / b ) T(n/b) T(n/b)。函数 f ( n ) f(n) f(n)包含了问题分解和子问题解合并的代价。
从技术的正确性方面看,此递归式并不是良好定义的,因为 n / b n/b n/b可能不是整数。但将 T ( n / b ) T(n/b) T(n/b)替换成 T ( ⌊ n / b ⌋ ) T(\lfloor{n/b}\rfloor) T(n/b)或者 T ( ⌈ n / b ⌉ ) T(\lceil{n/b}\rceil) T(n/b),并不影响递归的渐近性质。

主定理

主方法依赖于主定理。
定理 a ≥ 1 a\ge1 a1 b > 1 b>1 b>1是常数, f ( n ) f(n) f(n)是一个函数, T ( n ) T(n) T(n)是定义在非负整数上的递归式:
T ( n ) = a T ( n / b ) + f ( n ) T(n)=aT(n/b)+f(n) T(n)=aT(n/b)+f(n)
其中 n / b n/b n/b可以看作 ⌊ n / b ⌋ \lfloor{n/b}\rfloor n/b或者 ⌈ n / b ⌉ \lceil{n/b}\rceil n/b。那么 T ( n ) T(n) T(n)有如下渐近界:

  1. 若对于某个常数 ε > 0 \varepsilon>0 ε>0 f ( n ) = O ( n l o g b a − ε ) f(n)=O(n^{log_b{a-\varepsilon}}) f(n)=O(nlogbaε),则 T ( n ) = Θ ( n l o g b a ) T(n)=\Theta(n^{log_ba}) T(n)=Θ(nlogba)
  2. f ( n ) = Θ ( l o g b a ) f(n)=\Theta(log_ba) f(n)=Θ(logba),则 T ( n ) = Θ ( n l o g b a l g n ) T(n)=\Theta(n^{log_ba}{lgn}) T(n)=Θ(nlogbalgn)
  3. 若对于某个常数 ε > 0 \varepsilon>0 ε>0 f ( n ) = Ω ( n l o g b a + ε ) f(n)=\Omega(n^{log_b{a+\varepsilon}}) f(n)=Ω(nlogba+ε),且对某个常数 c < 1 c<1 c<1和所有足够大的 n n n a f ( n / b ) ≤ c f ( n ) af(n/b)\le{c}f(n) af(n/b)cf(n),则 T ( n ) = Θ ( f ( n ) ) T(n)=\Theta(f(n)) T(n)=Θ(f(n))

对于三种情况的每一种,我们将函数 f ( n ) f(n) f(n)与函数 n l o g b a n^{log_ba} nlogba进行比较。若函数 n l o g b a n^{log_ba} nlogba更大,如情况1,则解为 T ( n ) = Θ ( n l o g b a ) T(n)=\Theta(n^{log_ba}) T(n)=Θ(nlogba)。若函数 f ( n ) f(n) f(n)更大,如情况3,则解为 T ( n ) = Θ ( f ( n ) ) T(n)=\Theta(f(n)) T(n)=Θ(f(n))。若两个函数相等,如情况2,则乘上一个对数因子,解为 T ( n ) = Θ ( n l o g b a l g n ) = Θ ( f ( n ) l g n ) T(n)=\Theta(n^{log_ba}lg{n})=\Theta(f(n)lgn) T(n)=Θ(nlogbalgn)=Θ(f(n)lgn)

在此直觉之外,我们需要了解一些技术细节。在第一种情况中,不是 f ( n ) f(n) f(n)小于 n l o g b a n^{log_ba} nlogba就够了,而是要多项式意义上的小于。也就是说, f ( n ) f(n) f(n)必须渐近小于 n l o g b a n^{log_ba} nlogba,要相差一个因子 n ε n^\varepsilon nε,其中 ε \varepsilon ε是大于0的常数。在第三种情况中,不是 f ( n ) f(n) f(n)大于 n l o g b a n^{log_ba} nlogba就够了,而是要多项式意义上的大于,而且还要满足“正则”条件 a f ( n / b ) ≤ c f ( n ) af(n/b)\le{cf(n)} af(n/b)cf(n)。我们将会遇到的多项式界的函数中,多数都满足此条件。

需要注意的是,这三种情况并未覆盖 f ( n ) f(n) f(n)的所有可能性。情况1和情况2之间有一定的间隙, f ( n ) f(n) f(n)可能小于 n l o g b a n^{log_ba} nlogba但不是多项式意义上的小于。类似地,情况2和情况3之间也存在一定的间隙, f ( n ) f(n) f(n)可能大于 n l o g b a n^{log_ba} nlogba但不是多项式意义上的大于。如果函数 f ( n ) f(n) f(n)落在这两个间隙中,或者情况3中要求的正则条件不成立,就不能使用主方法来求解递归式。

使用主方法

先来看一个例子: T ( n ) = 9 T ( n / 3 ) + n T(n)=9T(n/3)+n T(n)=9T(n/3)+n
我们有 a = 9 a=9 a=9 b = 3 b=3 b=3 f ( n ) = n f(n)=n f(n)=n,因此 n l o g b a = n l o g 3 9 = Θ ( n 2 ) n^{log_ba}=n^{log_39}=\Theta(n^2) nlogba=nlog39=Θ(n2)。由于 f ( n ) = O ( n l o g 3 9 − ε ) f(n)=O(n^{log_3{9-\varepsilon}}) f(n)=O(nlog39ε),其中 ε = 1 \varepsilon=1 ε=1,因此可以应用主定理的情况1,从而得到解 T ( n ) = Θ ( n 2 ) T(n)=\Theta(n^2) T(n)=Θ(n2)

再看例子: T ( n ) = T ( 2 n / 3 ) + 1 T(n)=T(2n/3)+1 T(n)=T(2n/3)+1
其中 a = 1 a=1 a=1 b = 3 / 2 b=3/2 b=3/2 f ( n ) = 1 f(n)=1 f(n)=1,因此 n l o g b a = n l o g 3 / 2 1 = n 0 = 1 n^{log_ba}=n^{log_{3/2}1}=n^0=1 nlogba=nlog3/21=n0=1。由于 f ( n ) = Θ ( n l o g b a ) = Θ ( 1 ) f(n)=\Theta(n^{log_ba})=\Theta(1) f(n)=Θ(nlogba)=Θ(1),因此应用情况2,从而得到解 T ( n ) = Θ ( l g n ) T(n)=\Theta(lgn) T(n)=Θ(lgn)

对于递归式: T ( n ) = 3 T ( n / 4 ) + n l g n T(n)=3T(n/4)+nlgn T(n)=3T(n/4)+nlgn
其中 a = 3 a=3 a=3 b = 4 b=4 b=4 f ( n ) = n l g n f(n)=nlgn f(n)=nlgn,因此 n l o g b a = n l o g 4 3 = O ( n 0.793 ) n^{log_ba}=n^{log_43}=O(n^{0.793}) nlogba=nlog43=O(n0.793)。由于 f ( n ) = Ω ( n l o g 4 3 + ε ) f(n)=\Omega(n^{log_4{3+\varepsilon}}) f(n)=Ω(nlog43+ε),其中 ε ≈ 0.2 \varepsilon\approx0.2 ε0.2,因此,如果可以证明正则条件成立,即可应用情况3。当 n n n足够大时,对于 c = 3 / 4 c=3/4 c=3/4 a f ( n / b ) = 3 ( n / 4 ) l g ( n / 4 ) ≤ ( 3 / 4 ) n l g n = c f ( n ) af(n/b)=3(n/4)lg(n/4)\le(3/4)nlgn=cf(n) af(n/b)=3(n/4)lg(n/4)(3/4)nlgn=cf(n)。因此,由情况3,递归式的解为 T ( n ) = Θ ( n l g n ) T(n)=\Theta(nlgn) T(n)=Θ(nlgn)

主方法不能递归式: T ( n ) = 2 T ( n / 2 ) + n l g n T(n)=2T(n/2)+nlgn T(n)=2T(n/2)+nlgn
虽然这个递归式看起来有恰当的形式: a = 2 a=2 a=2 b = 2 b=2 b=2 f ( n ) = n l g ( n ) f(n)=nlg(n) f(n)=nlg(n),以及 n l o g b a = n n^{log_ba}=n nlogba=n。你可能想到要用情况3,因为 f ( n ) = n l g n f(n)=nlgn f(n)=nlgn渐近大于 n l o g b a = n n^{log_ba}=n nlogba=n。问题出在它并不是多项式意义上的大于。对任意正常数 ε \varepsilon ε,比值 f ( n ) / n l o g b a = ( n l g n ) / n = l g n f(n)/n^{log_ba}=(nlgn)/n=lgn f(n)/nlogba=(nlgn)/n=lgn都渐近小于 n ε n^\varepsilon nε。因此,递归式落入了情况2和情况3之间的间隙。

如果遇到不能用主方法解决的递归式,就要试着利用递归树或者代入法进行求解。具体的求解过程,可以参照算法导论第四章内容。

### 回答1: 时间复杂度求解取决于实际的算法,一般可以分析算法的执行步骤,统计每个步骤所用的时间,从而求得时间复杂度。对于递归算法,可以通过分析递归函数的执行次数,以及每次调用递归函数所消耗的时间,来求解时间复杂度。 ### 回答2: 要求解递归时间复杂度,我们可以按照以下步骤进行: 1. 首先,确定递归的形。递推通常具有递归的特点,即问题的规模需要通过不断缩小来递归求解。例如,递归可能包含递归调用,或者具有递归的结构。 2. 其次,推导递归递归深度。递归时间复杂度通常与递归的深度相关,即需要确定递归递归深度。 3. 然后,分析递归函数的时间代价。将递归的执行过程分解为不同的子问题,确定每个子问题的时间代价。这可能涉及到递归子问题的规模和计算时间。 4. 最后,通过递归的时间代价和递归递归深度来确定递归时间复杂度。 需要注意的是,递归时间复杂度可能与递归的规模有关,也可能与递归的深度有关,具体取决于具体的情况和问题的性质。同时,递归时间复杂度也可能需要通过数学推导或递归树等方法进行求解。 总的来说,求解递归时间复杂度需要通过对递归的分析、递归深度的确定以及递归函数的时间代价的分析来进行。 ### 回答3: 求解递归时间复杂度需要以下步骤: 1. 确定递归的形:首先,我们需要确定递归的形递归方程,即描述递归的基本操作和递归关系的数学等。这通常需要根据问题的特点和递归的实现进行分析。 2. 求解递归方程:接下来,我们需要求解递归方程,即找到递归的解析解。这可以通过代入法、特征根法或母函数法等数学方法来实现。在这一步骤中,我们可以得到递归的通项公,并进一步进行化简。 3. 分析递归时间复杂度:一旦我们得到递归的通项公,我们可以通过分析公的增长率来确定递归时间复杂度。具体来说,我们可以评估递归中的递归调用次数和每次递归操作的时间复杂度,然后将它们相乘得到最终的时间复杂度。 4. 解决递归的边界条件:最后,我们需要解决递归的边界条件,即递归的终止条件。这是因为递归只有在满足终止条件时才能收敛,否则递归会无限进行下去。在分析时间复杂度时,我们需要考虑递归的基本操作在边界条件下的执行次数和时间复杂度。 需要注意的是,求解递归时间复杂度可能涉及到数学推理和推导,需要运用到数学分析的方法。具体的求解过程会根据不同的递归和问题而有所不同。同时,我们也可以借助工具和数值计算对递归进行近似求解,以便更好地估计时间复杂度的上界和下界。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值