递归算法复杂度?

问题描述

我之前有以下问题:

给定一个递归算法T(n),找到一个函数f(n),其中 T(n)=\theta( f(n) )

注意: k 是常数且 3,对于 n, T(n)=0

T(n)=\left(\sum_{i=1}^{\log n} T\left(\left\lfloor \frac{n}{k^i} \right\rfloor\right)\right) + n

我该如何解决这样的问题?

解决方法

好吧,我不会展示我所有的步骤。这是您的家庭作业问题,但这里有一个概述:

  • 基于递归定义,我们可以分解求和:

    T(n) = 
        n 
      + T(floor(n / k)) 
      + T(floor(n / k ^ 2)) 
      + ... 
      + T(floor(n / (k ^ log(n))))
    
  • 那么由此,我们可以得到一个迭代定义:

      T(n) = 
          n 
          + floor(n / k) 
          + 2 * floor(n / k ^ 2) 
          + ... 
          + 2 ^ (log(n) - 1) 
              * floor(n / k ^ (log(n)))
    

    T(n) = 
      n 
      + Sum(
          floor(n / k ^ i) * 2 ^ (i),i=1,log(n)
      ) / 2
    

您的问题需要大 Theta。这意味着我们需要找出一个上限和下限。

  • 上限:floor(x) <= x,所以我们放下地板并简化:

    O(
        n + n / (k - 2)                       <-- O(n)
        + (n * (2 / k) ** log(n)) / (k - 2)
    )
    

    因为 k > 3 > 2,最后一项保证增长小于 n,所以我们剩下 O(n)

  • 下限:总是 Sum(...) > 0,所以我们可以只用 n 将其绑定在下面,给出 Omega(n)

因为T对于O(f(n))既是Omega(f(n))又是f(n) = n,所以我们可以说它也是Theta(n),所以答案是

f(n) = n

这是一个演示上限和下限的程序。该程序不等同于证明,但它可以帮助您了解正在发生的事情。我以指数方式增长 n,因此如果您在对数刻度上绘制值,它应该显示线条和渐近行为。

const k = 4;
const logK = Math.log(k);

function T(n) {
  if (n <= 1)
   return 0;
  
  let acc = n;
  for (let i = 1; i <= Math.log(n) / logK; i++)
    acc += T(Math.floor(n * k ** -i));
  
  return acc;
}

function nonRecT(n) {
  let acc = n;
  for (let i = 1; i <= Math.log(n) / logK; i++) {
    let f = Math.floor(n * k ** -i);
    acc += f > 1 ? f * 2 ** (i - 1) : 0;
  }
  return acc;
}

for (let n = k; n <= k ** 20; n *= k) {
  console.log([
    n,T(n),nonRecT(n),n * (1.5 + 1 / (k - 2))
  ].join('\t'));
}