【发布时间】:2020-07-30 09:44:36
【问题描述】:
我认为这个递归的复杂度是 O(n^2/3)`,通过改变变量和归纳。但我不确定。这个解决方案正确吗?
【问题讨论】:
标签: algorithm recursion math time-complexity complexity-theory
我认为这个递归的复杂度是 O(n^2/3)`,通过改变变量和归纳。但我不确定。这个解决方案正确吗?
【问题讨论】:
标签: algorithm recursion math time-complexity complexity-theory
这是一个引人入胜的递归,它确实没有解出 Θ(n)。相反,它似乎解决了 Θ(n2/3)。
为了直观说明为什么这不可能是 Θ(n),让我们假设我们正在处理一个非常非常大的 n 值。那么由于
T(n) = (nT(√n) + n)1/2
假设 T(√n) ≈ √n,我们会得到这个
T(n) = (n√n + n)1/2
= (n3/2 + n)1/2
≈n3/4.
换句话说,假设 T(n) = Θ(n) 随着 n 变大,我们会得到一个不同的 T(n) 值。
另一方面,我们假设 T(n) = Θ(n2/3)。然后同样的计算告诉我们
T(n) = (nT(n) + n)1/2
= (n·n2/3 + n)1/2
&大约; (n4/3)1/2
= n2/3,
与自身一致。
为了验证这一点,我编写了一个简短的程序,在给定不同输入的情况下打印出不同的 T(n) 值并绘制结果。这是我写的 T(n) 的版本:
double T(double n) {
if (n <= 2) return n;
return sqrt(n * T(sqrt(n)) + n);
}
我决定使用 2 作为基本情况,因为反复取平方根永远不会让 n 下降到 1。我还决定使用实值参数而不是离散整数值,只是为了使数学更容易。
如果你绘制 T(n) 的值,你会得到这条曲线:
这看起来不像我对线性图的期望。为了弄清楚这是什么,我将它绘制在对数/对数图上,它具有一个很好的特性,即所有多项式函数都转换为斜率等于指数的直线。结果如下:
我咨询了我的 Handy Neighborhood Regression Software 并要求它确定这条线的斜率。以下是它回馈的内容:
坡度:0.653170918815869
R2:0.999942627574643
这是一个非常很好的拟合,0.653 的斜率非常接近 2/3。所以这是更多的经验证据支持递归求解到 Θ(n2/3)。
现在剩下要做的就是计算数学。我们将使用一系列替换来解决这种重复。
首先,我一般不太习惯以这种递归方式使用指数的方式使用它们,所以让我们记录双方的日志。 (在整个阐述中,我将使用 lg n 来表示 log2 n)。
lg T(n) = lg (nT(√n) + n)1/2
= (1/2) lg (nT(√n) + n)
= (1/2) lg(T(√n) + 1) + (1/2)lg n
≈ (1/2) lg T(√n) + (1/2) lg n
现在,让我们定义 S(n) = lg T(n)。然后我们有
S(n) = lg T(n)
≈ (1/2) lg T(√ n) + (1/2) lg n
= (1/2) S(√ n) + (1/2) lg n
这更容易处理,尽管我们仍然存在每次幂次递减的问题。为了解决这个问题,让我们再做一次替换,这在处理这类表达式时是相当常见的。让我们定义 R(n) = S(2n)。然后我们就有了
R(n) = S(2n)
&大约; (1/2)S(√2n) + (1/2) lg 2n
= (1/2)S(2n/2) + (1/2) n
= (1/2) R(n / 2) + (1/2) n
太棒了!现在剩下要做的就是求解 R(n)。
现在,这里有一个小问题。我们可以立即使用主定理得出 R(n) = Θ(n) 的结论。这样做的问题是,仅仅知道 R(n) = Θ(n) 不会让我们确定 T(n) 是什么。具体来说,假设我们只知道 R(n) = Θ(n)。那么我们可以这么说
S(n) = S(2lg n) = R(lg n) = Θ(log n)
得到 S(n) = Θ(log n)。然而,当我们试图根据 S(n) 求解 T(n) 时,我们会遇到困难。具体来说,我们知道
T(n) = 2S(n) = 2Θ(log n),
但是我们不能从这个出发去说 T(n) = Θ(n)。原因是 Θ(log n) 中的隐藏系数在这里很重要。具体来说,如果 S(n) = k lg n,那么我们就有了
2k lg n = 2lg nk = nk,
所以对数的前导系数最终将确定多项式上的指数。因此,在求解R时,需要确定线性项的准确系数,转化为S的对数项的准确系数。
让我们回到 R(n),我们知道是
R(n) & 约; (1/2) R(n/2) + (1/2)n。
如果我们重复几次,我们会看到这种模式:
R(n) & 约; (1/2) R(n/2) + (1/2)n
&大约; (1/2)((1/2) R(n/4) + (1/4)n) + (1/2)n
&大约; (1/4)R(n/4) + (1/8)n + (1/2)n
&大约; (1/4)((1/2)R(n/8) + n/8) + (1/8)n + (1/2)n
&大约; (1/8)R(n/8) + (1/32)n + (1/8)n + (1/2)n。
模式似乎是,经过 k 次迭代,我们得到了
R(n) & 约; (1/2k)R(n/2k) + n(1/2 + 1/8 + 1/32 + 1/128 + ... + 1/22k+1)。
这意味着我们应该查看总和
(1/2) + (1/8) + (1/32) + (1/128) + ...
这是
(1/2)(1 + 1/4 + 1/16 + 1/64 + ... )
作为几何级数之和,求解为
(1/2)(4/3)
= 2/3。
嘿,看!这是我们之前所说的2/3。这意味着对于取决于递归基本情况的某个常数 c,R(n) 的结果约为 (2/3)n + c。因此,我们看到
T(n) = 2S(n)
= 2S(2lg n)
= 2R(lg n)
&大约; 2(2/3)lg n + c
= 2lg n2/3 + c
= 2c 2lg n2/3
= 2c n2/3
= Θ(n2/3)
这与之前的理论预测值和经验观察值相匹配。
这是一个非常有趣的问题,我承认我对答案感到惊讶!不过,我有点紧张,因为我可能在出发时错过了一些东西
lg T(n) = (1/2) lg (T(√n) + 1) + (1/2) lg n
到
lg T(n) & 约; (1/2) lg T(√ n) + (1/2) lg n。
这个 +1 术语实际上可能在我不认识的循环中引入了一些其他术语。例如,是否会产生一个 O(log log n) 项? That wouldn't surprise me,假设我们有一个以平方根缩小的递归。但是,我已经进行了一些简单的数据探索,但我没有看到任何看起来涉及双对数的术语。
希望这会有所帮助!
【讨论】:
T(n) = sqrt(n*T(sqrt(n)) + n)
我们将双方都提高到 2 的幂:
[T(n)]^2 = n*T(sqrt(n)) + n
将n从两边分开:
{[T(n)]^2 / n} = T(sqrt(n) + 1
让m 等于log(n) 因此,n 将等于2^m
{[T(2^m)]^2 / 2^m} = T(sqrt(2^m) + 1
我们将定义一个新函数S(m) = {[T(2^m)]^2 / 2^m}
S(m) = T(m/2) + 1
根据 Mater 定理等于 θ(log(m)) = θ(log(log(n)))
所以我们知道:
{[T(n)]^2 / n} = θ(log(log(n)))
两边乘以n得到:
[T(n)]^2] = θ(n*log(log(n)))
因此,
T(n) = θ(sqrt(n*log(log(n))))
【讨论】:
我们知道:
T(n) = sqrt(n) * sqrt(T(sqrt(n)) + 1)
因此:
T(n) < sqrt(n) * sqrt(T(sqrt(n)) + T(sqrt(n)))
1 被 T(sqrt(n)) 替换。所以,
T(n) < sqrt(2) * sqrt(n) * sqrt(T(sqrt(n))
现在,要找到一个上限,我们需要解决以下循环关系:
G(n) = sqrt(2n) * sqrt(G(sqrt(n))
为了解决这个问题,我们需要扩展它(假设n = 2^{2^k}和T(1) = 1):
G(n) = (2n)^{1/2} * (2n)^{1/8} * (2n)^{1/32} * ... * (2n)^(1/2^k) =>
G(n) = (2n)^{1/2 + 1/8 + 1/32 + ... + 1/2^k} =
如果我们从1/2 + 1/8 + 1/32 + ... + 1/2^k 中取一个因子1/2,我们将得到1/2 * (1 + 1/4 + 1/8 + ... + 1/2^{k-1})。
正如我们所知,1 + 1/4 + 1/8 + ... + 1/2^{k-1} 是一个几何级数,其比率为1/4,它在无穷远处等于4/3。因此G(n) = Theta(n^{2/3}) 和T(n) = O(n^{2/3})。
请注意,作为sqrt(n) * sqrt(T(sqrt(n)) < T(n),我们可以显示类似于前面T(n) = Omega(n^{2/3}) 的情况。这意味着T(n) = Theta(n^{2/3})。
【讨论】: