使用递归方程的程序的时间复杂度
Posted
技术标签:
【中文标题】使用递归方程的程序的时间复杂度【英文标题】:Time complexity of the program using recurrence equation 【发布时间】:2013-03-13 19:33:27 【问题描述】:我想使用递归方程找出程序的时间复杂度。 那是..
int f(int x)
if(x<1) return 1;
else return f(x-1)+g(x);
int g(int x)
if(x<2) return 1;
else return f(x-1)+g(x/2);
我写了它的递归方程并试图解决它,但它不断变得复杂
T(n) =T(n-1)+g(n)+c
=T(n-2)+g(n-1)+g(n)+c+c
=T(n-3)+g(n-2)+g(n-1)+g(n)+c+c+c
=T(n-4)+g(n-3)+g(n-2)+g(n-1)+g(n)+c+c+c+c
……………………….
……………………..
Kth time …..
=kc+g(n)+g(n-1)+g(n-3)+g(n-4).. .. . … +T(n-k)
Let at kth time input become 1
Then n-k=1
K=n-1
Now i end up with this..
T(n)= (n-1)c+g(n)+g(n-1)+g(n-2)+g(n-3)+….. .. g(1)
我无法进一步解决它。 无论如何,如果我们计算这个程序中的函数调用次数,很容易看出时间复杂度是指数级的,但我想用递归来证明它。怎么办?
Anwer 1 中的解释,看起来正确,我做过类似的工作。
这段代码中最困难的任务是写出它的递归方程。我画了另一张图,我确定了一些模式,我想我们可以从这张图得到一些帮助,什么是可能的递归方程。
And I came up with this equation , not sure if it is right ??? Please help.
T(n) = 2*T(n-1) + c * logn
【问题讨论】:
确切的问题是什么?你想证明某个 c > 1 的 T_f(x) = Theta(c^x) 吗?或者你想要一个精确的公式? g也一样? 这段代码很混乱,我们需要同时考虑函数f(x)和g(x)... 您需要求解g(x) = 2g(x - 1) - g((x - 1) / 2) + g(x / 2)
,然后将其重新插入 f(x)
以求解 f(x)。
@nhahtdh 你是从哪里得到这个等式的?
@sidstuff: 获胜者是......? Knoothe 先生给出了最严格的界限,他的回答值得被接受,i.m.o,尽管我同意 Saeed 的观点,即 2^n 和 3^n 之间没有太大的实际区别。请不要告诉我们你的老师(这是家庭作业,不是吗?)说 O(n) 是答案(虽然......然后我赢了:-) 顺便说一句:我喜欢这个问题和讨论,先生们!
【参考方案1】:
好的,我想我已经能够证明f(x) = Theta(2^x)
(注意时间复杂度是一样的)。这也证明g(x) = Theta(2^x)
等于f(x) > g(x) > f(x-1)
。
首先正如大家所说,很容易证明f(x) = Omega(2^x)
。
现在我们有了f(x) <= 2 f(x-1) + f(x/2)
(因为f(x) > g(x)
)的关系
我们将证明,对于足够大的x
,有一些常数K > 0
使得
f(x) <= K*H(x), where H(x) = (2 + 1/x)^x
这意味着f(x) = Theta(2^x)
,作为H(x) = Theta(2^x)
,它本身是由H(x)/2^x -> sqrt(e) as x-> infinity
(wolfram alpha链接的限制)这一事实得出的。
现在(警告:较重的数学,也许 cs.stackexchange 或 math.stackexchange 更适合)
根据wolfram alpha(点击链接查看x = infinity附近的级数展开),
H(x) = exp(x ln(2) + 1/2 + O(1/x))
再一次,根据wolfram alpha(点击链接(与上面不同)并查看 x = infinity 的级数展开式),我们有这个
H(x) - 2H(x-1) = [1/2x + O(1/x^2)]exp(x ln(2) + 1/2 + O(1/x))
等等
[H(x) - 2H(x-1)]/H(x/2) -> infinity as x -> infinity
因此,对于足够大的x
(比如x > L
),我们有不等式
H(x) >= 2H(x-1) + H(x/2)
现在有一些K
(仅依赖于L
(例如K = f(2L)))这样
f(x) <= K*H(x) for all x <= 2L
现在我们通过(强)归纳法(如果您愿意,可以恢复为自然数)
f(x+1) <= 2f(x) + f((x+1)/2)
通过归纳,右边是
<= 2*K*H(x) + K*H((x+1)/2)
我们之前已经证明了这一点
2*H(x) + H((x+1)/2) <= H(x+1)
因此f(x+1) <= K * H(x+1)
【讨论】:
@Saeed 加油!我们所有的证明都使用相同的递归 H(n) = 2H(n-1) + H(n/2) (我什至计算了加法,作为一个非常注重成本的荷兰人......)你和我都差强人意证明 O(2^n)。 Knoothes 聪明的想法是使用系列 (2+1/n)^n 显然(在擦亮我的眼镜之后:-) 在 O(2^n) (2+ε)^n 使用 fixed epsilon,不会得到 O(2^n)。 (2+1/n)^n 使用 递减 epsilon,并得到结果。 @SaeedAmiri:顺便说一句,这个证明的核心是H(x) >= 2H(x-1) + H(x/2)
(这是最困难的部分)。我刚刚看到对您的回答进行了编辑,但仍在挥手。你不能像那样用 1/n 替换 epsilon !您正在跳过证明中最难的部分。如果您不同意,您是否会考虑在 math.stackexchange 上发帖以获得专家级 cmets?
你基本上是在那儿挥手。
@SaeedAmiri:第一个错误无关紧要,因为您似乎只使用 if to f(n) <= 2f(n-1) + f(n/2)
,这很容易看到(例如,请参阅我的答案)。很明显,重点是找到一个上限(因为下限是微不足道的)。对于 c > 2(即本质上是 (2+epsilon)^n),证明 c^x 的上界容易。困难的部分是提出一个上限,它本身就是 O(2^x)。您的答案完全缺乏这一点,并且您当前的方法不起作用(这就是 HansLub 说答案不足时的意思)。【参考方案2】:
使用memoisation,可以在 O(n) 时间内轻松计算这两个函数。但是 程序 至少需要 O(2^n) 时间,因此是计算 f(n)
和 g(n)
的一种非常低效的方法
为了证明程序在最多 O(2+epsilon)^n 时间对于任何epsilon > 0:
令 F(n) 和 G(n) 分别是在计算 f(n) 和 g(n) 时进行的函数调用次数。显然(将添加计为 1 个函数调用):
F(0) = 1; F(n) = F(n-1) + G(n) + 1 G(1) = 1; G(n) = F(n-1) + G(n/2) + 1
那么可以证明:
F 和 G 是单调的 F > G 定义 H(1) = 2; H(n) = 2 * H(n-1) + H(n/2) + 1 显然,H > F 对于所有 n,H(n) > 2 * H(n-1) 因此 H(n/2) / H(n-1) -> 0 表示足够大的 n 因此 H(n) 0 且足够大的 n 因此对于任何 epsilon > 0 的 O((2 + epsilon)^n) 中的 H (编辑:最初我在这里得出的结论是上限是 O(2^n)。这是不正确的,正如 nhahtdh 指出的那样,但见下文) 所以这是我能证明的最好的......因为 G 0,它们也在 O((2 + epsilon)^n) 中后记(在看到 Knoothes 先生的解决方案之后):因为 i.m.h.o 一个好的数学证明可以提供洞察力,而不是大量的公式,并且所有这些后代都存在 SO(嗨,女士们!):
对于许多算法,计算 f(n+1) 涉及两倍(三次,..)f(n) 的工作量,加上更多。如果随着 n 的增加(通常是这种情况),使用像上面这样的固定 epsilon 会变得相对更少,这不是最佳的。 用 n 的某个递减函数 ε(n) 替换上面的 epsilon 在许多情况下(如果 ε 下降得足够快,例如 ε(n)=1/n)会产生一个上限 O((2 + ε(n))^ n ) = O(2^n)
【讨论】:
2^n 是下限,所以你应该说它是 Omega(2^n)。 证明的步骤看起来如此挥手,让我脊背发凉...... 但这不是你下沉证明的方式。哪一步失败了,为什么?hence H in O((2 + epsilon)^n) for any epsilon > 0 hence H in O(2^n)
这一步看起来有点可疑。由于 2 + epsilon > 2,当 n --> Inf 时不会 lim (2 + epsilon)^n / 2^n --> Inf?那么 H 不在 O(2^n) 中。
如果有一个反例就更好了:(2^n) * log(n) 对于任何大于 0 的 epsilon 都在 O((2 + epsilon)^n) 中,但不在 O(2^n) 中.所以我的证明是不正确的。【参考方案3】:
令 f(0)=0 且 g(0)=0
从我们拥有的功能来看,
f(x) = f(x - 1) + g(x)
g(x) = f(x - 1) + g(x/2)
将 g(x) 代入 f(x) 我们得到,
f(x) = f(x-1) + f(x -1) + g(x/2)
∴f(x) = 2f(x-1) + g(x/2)
我们得到扩展,
f(x) = 2f(x-1)+f(x/2-1)+f(x/4-1)+ ... + f(1)
设 s(x) 为如下定义的函数,
s(x) = 2s(x-1)
现在显然 f(x)=Ω(s(x))。
s(x)的复杂度是O(2x)。
因此函数 f(x)=Ω(2x)。
【讨论】:
下界很清楚。更有趣的方面是上限。 -1:因为没有证明任何不平凡的事情,以及以后的错误陈述。 @Deepu:感谢您的收听,但是(不要粗鲁),我真的不认为这个答案值得它得到的支持。您所展示的只是 f(x) = Omega(2^x),这很容易展示。困难的部分是证明 f(x) = O(2^x)。 (nhahtdh 也评论了相同的行)。因此,反对票成立。对于那个很抱歉。顺便说一句,只需 s(x) = 2s(x-1) 就足够了,不是吗?为什么要加 c?【参考方案4】:我认为很清楚 f(n) > 2n,因为 f(n) > h(n) = 2h(n-1) = 2n支持>.
现在我声称对于每个 n,都有一个 ε 使得: f(n) n,要看到这一点,让我们通过归纳来做,但首先为了更合理,我将使用 ε = 1、显示f(n) n,那我就扩展一下。
我们将使用强归纳,假设对于每个 m m 那么我们有:
f(n) = 2[f(n-1) + f(n/2 -1) + f(n/4 -1)+ ... +f(1-1)]
但对于这部分:
A = f(n/2 -1) + f(n/4 -1)+ ... +f(1-1)
我们有:
f(n/2) = 2[f(n/2 -1) + f(n/4 -1)+ ... +f(1-1]) ==>
A <= f(n/2) [1]
所以我们可以重写 f(n):
f(n) = 2f(n-1) + A < 2f(n-1) +f(n/2),
现在回到我们的主张:
f(n) < 2*3^(n-1) + 2*3^(n/2)==>
f(n) < 2*3^(n-1) + 3^(n-1) ==>
f(n) < 3^n. [2]
通过[2],完成了f(n)∈O(3n)的证明。
但是如果你想把这个扩展成(2+ε)n的格式,只要用1来代替不等式,那么我们就有
对于 ε > 1/(2+ε)n/2-1 → f(n) n.[3]
也可以通过 [3] 说,对于每个 n 都有一个 ε,使得 f(n) n 实际上存在常数 ε,因此对于 n > n0,f(n)∈O((2+ε)n)。 [4]
现在我们可以像@Knoothe 一样使用wolfarmalpha,通过设置ε=1/n,那么我们将有:
f(n) n 得到 f(n) n,并且我们的简单下限为开始我们有: f(n)∈ Θ(2^n).[5]
PS:我没有准确计算epsilon,但是你可以简单地用笔和纸来计算,我认为这个epsilon不正确,但很容易找到它,如果很难告诉我很难,我会写的。
【讨论】:
是的,您的最后结论不仅适用于 一些 epsilon,而且适用于 every epsilon > 0 @HansLub,在O
表示法中,当我们说每个 n > n0 时,意味着 n0 是常数,如果你看一下 epsilon 和 n0 之间的关系,epsilon 依赖于 n0,所以我不能说每个 epsilon,因为 n0 是固定的,所以我应该关注 n0 而不是 epsilon,而不是说对于任何 epsilon 都存在 n0,我应该说对于每个固定的 n0 都存在 epsilon 这样......,并且重点是这个,我们应该找到 n0 的 epsilon。
当你说 f 在 O(g) 中时,你不需要提到 n0;您已经声明存在 c 和 n0,使得 f(n) n0。正如你所说,不仅对于任何 n0 存在一个 epsilon,而且对于任何 epsilon 都存在一个 n0 使得 .... 因此对于任何 epsilon,f 在 O((2+epsilon)^n)
@HansLub,实际上我不同意所有的 epsilon 都存在 n0 这样......,因为当 epsilon 无限小时,n0 将无限大,然后 n0 不是固定常数。
@HansLub:我现在可以自信地说,这里的答案有问题。 f(x) = w(2^x)
不对。事实上,f(x) = Theta(2^x)
!请看我的答案与证明。 (当然,错误可能在我的证明中,但我没有在任何地方挥手,每一步都很容易验证)以上是关于使用递归方程的程序的时间复杂度的主要内容,如果未能解决你的问题,请参考以下文章