递归式的代入法

代入法是一种用于求解递归算法时间复杂度的技术,它通过展开递归关系式、识别模式,然后利用数学归纳法来证明结果。

  • 理解递归是如何工作的。
  • 写出递归关系式。
  • 根据递归模式猜测解。
  • 利用数学归纳法验证猜测的解。

让我们通过下面的示例代码来理解上述步骤。

C++


CODEBLOCK_1e15bf1f

Java


CODEBLOCK_ff38670e

Python


CODEBLOCK_2c922485

C#


CODEBLOCK_937949d6

JavaScript


CODEBLOCK_7e39d3a2

理解此代码中的递归

  • 每次调用该函数时,它都会打印一次 "GFG"
  • 它会进行两次递归调用,每次的输入规模都是 n/2
  • n <= 0 时,递归停止。

写出递归关系式

每个函数调用中完成的工作是常量级的(打印 INLINECODEa81c2d91),并且该函数进行了两次规模为 INLINECODE820cbb70 的递归调用。因此,递归关系式为: T(n) = 2T(n/2) + O(1)

应用代入法

为了猜测递归的解,我们分析该函数产生的递归调用次数。

每个函数调用只执行常量级的工作,并将问题拆分为两个规模为 n/2 的子问题。

随着递归的继续,函数调用的数量在每一层都会翻倍,并且当输入规模变为常量时递归停止,这大约发生在 log n 层之后。

因此,我们猜测时间复杂度为 T(n) = O(n)。

> 现在,我们来验证这个猜测。

> 假设对于某个常数 c > 0: T(n) ≤ cn

>

> 假设这对于较小的 n 值成立,特别是对于 n/2: T(n/2) ≤ c(n/2)

>

> 代入递归关系式:

> T(n) = 2T(n/2) + O(1)

>      ≤ 2 · c(n/2) + O(1)

>      = cn + O(1)

> 对于足够大的 n 值,常数项会被 cn 主导。

> 因此, T(n) ≤ cn

结果: 假设成立,这证实了该递归的时间复杂度为: T(n) = O(n)

归并排序示例

请参考 归并排序代码 作为下一个示例。在每次函数调用中,数组被分成两半,并进行了两次递归调用,每次都在大小为 n/2 的子数组上操作。在递归调用之后,函数执行线性工作来合并这两个已排序的半部分。因此,递归关系式为: T(n) = 2T(n/2) + n

应用代入法

为了猜测递归的解,我们分析函数在递归的每一层所做的工作。每个函数调用将数组分为两个大小为 n/2 的子数组并进行两次递归调用。在递归调用返回后,函数执行线性工作来合并这两个已排序的半部分。

随着递归的进行,子问题的数量在每一层都翻倍,而每个子问题的规模则减半。当子数组大小变为常量时递归停止,这大约发生在 log n 层之后。在递归树的每一层,完成的总工作量都与 n 成正比。

因此,我们猜测时间复杂度为: T(n) = O(n log⁡ n)

> 验证猜测:

>

> 假设对于某个常数 c > 0: T(n) ≤ c n log n

> 假设这对于较小的 n 值成立,特别是对于 n/2: T(n/2) ≤ c (n/2) log(n/2)

> 代入递归关系式:

> T(n) = 2T(n/2) + n

> ≤ 2 ⋅ c (n/2) log(n/2) + n

> = cn (log n – log 2) + n

> = cn log n – cn + n

>

> 对于足够大的 n 值,线性项会被 cn log n 主导。

> 因此, T(n) ≤ cn log n

结果: 假设成立,这证实了该递归的时间复杂度为: T(n) = O(n log n)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。如需转载,请注明文章出处豆丁博客和来源网址。https://shluqu.cn/37401.html
点赞
0.00 平均评分 (0% 分数) - 0