【问题标题】:time complexity for this algorithm with two for loops具有两个 for 循环的该算法的时间复杂度
【发布时间】:2014-02-01 20:19:05
【问题描述】:

你能解释一下如何计算时间复杂度

sum1=0;
for(k=1;k<=n;k*=2)
  for(j=1;j<n;j++)
     sum++

我以 N 为基数,并尝试计算发生了多少次迭代

n=1,2,3...n

但我无法概括它。 请有人彻底解释一下。 我什至检查了其他类似类型的查询,例如: 说它跟随

1,2,4,8...n so it will be
2^n
nlogn

但我不明白。 我不知道他们怎么说2^n=logn。 请任何正确解释如何逐步计算..

谢谢:)

【问题讨论】:

  • 但我的文字说:时间复杂度是 nLogn 。这就是为什么混淆
  • @JerryCoffin:文字说:#runs=(1+...N)LogN= j=1 到 logn of (n) = n logn 的总和
  • 能否引用n log n的全文。很难理解你的上下文。
  • 嘿,我真的很抱歉。增量写错了,我现在修改了

标签: algorithm time-complexity nested-loops binary-search logarithm


【解决方案1】:

k 呈指数增长,因此需要O(log n) 时间才能达到n。检查logarithm 的定义。那是你的外循环。

内部循环是一个简单的O(n)

【讨论】:

  • k 增长为 1,2,4,8, .... n 即 2^0, 2^1, 2^2 ..... 2^n。这是否意味着 O(2^n)
  • 您正在寻找步数。要达到 n=2^x,您需要 x 步。 x 是 log(n)。
  • 如果 k 增长 1,3,9,27 .. n,即 3 的幂。复杂度将保持与 logn 相同?
  • 是的。这在 O 表示法的常数因子内。如果您对数学感兴趣:您可以将对数改写为不同的底数,检查方程式。
  • @ndpu:所以你在这里评论无关紧要的事情只是因为我评论了你的答案?长大吧,伙计。
【解决方案2】:

为了获得两个循环的完整复杂度,您需要将外部循环的复杂度乘以内部循环的复杂度。这是通过考虑当 n 变得非常大时会发生什么(从技术上讲,因为 n 趋于无穷大)。您总共需要对 sum 或循环变量执行多少次操作?

在这种情况下,外部循环执行log(n) 次,因为 k 呈指数增长。指数地因为 k 在外循环的每次迭代中翻倍,所以这意味着它增长为 2^k,直到 2^k 达到 n。像这样乘以循环变量的注释。根据您在 cmets 中的问题,如果您将 k 乘以 3,您仍然会得到 log(n),但它将以 base-3 记录,而不是以 base-2 记录。渐近地,对数的基数不相关,因此您可以简单地说它是 log(n),忽略基数。因此,第一个循环具有O(log(n)) 复杂度。内部循环仍然是线性的(运行 n 次),因此如果将它们相乘,您将得到 O(n*log(n)) 复杂度。

总而言之:O(nlogn)

【讨论】:

  • 嘿,我真的很抱歉。增量写错了,我现在修改了
  • 如果 k 增加三倍,那会不会一样?时间复杂度会保持 logn 本身吗?
  • 是的,但是登录base-3,而不是ld(log base 2)。然而,渐近地,两个对数都是“等价的”,因此我们通常只说它是 log(n),而忽略了对数的基数。这有意义吗?
  • 感谢@Martin Dinov。还有一件事,我想知道的是。你是如何推断出 2^i 来登录的。我知道了程序。但如果我知道这件事怎么办。我认为时间复杂度是 O(n*(2^i))。
【解决方案3】:

鉴于您的问题结构:

sum1=0;
for(k=1;k<=n;k*=2)  // <-- Takes 1+1/2+1/2^2+1/2^3...+1/2^n = O(log(n)) time
   for(j=1;j<n;j++)  // <-- Takes 1+2+3+...+n = O(n) time
      sum++

外部循环将 k 的值增加k*2,因此您基本上每次都一半搜索空间:

k = 1*2 = 2 => 1/2^1 time
k = 2*2 = 4 => above + 1/2^2 time
k = 4*2 = 8 => above + 1/2^3 time
k = 8*2 = 16 => above + 1/2^4 time
.   .     .
.   .     .
.   .     .
k = n*2 = 2^n => above + 1/2^n time

换句话说,您每次都丢弃一半的元素。话虽如此,您实际上是在

中搜索大小为 n 的数组
1+(1/2)+(1/2^2)+(1/2^3)+...+(1/2^n) time = log(n) time

log(n) 是怎么来的?

以二叉树为例,在每个节点上,我们都分支成两个节点,这可以表示为递归关系:

T(n) = 2T(n/2)

随着搜索空间减少 2,当我们离根越远时,当搜索空间等于 1 时,我们必须达到 边界条件。深度为 k 的搜索空间大小将是 n/2^k(类似于我们上面看到的)

在搜索空间相等时,我们的等式变为:

n/2^k = 1
=> n = 2^k

Taking log on both sides:
=> log n = k log 2
=> log n/ log 2 = k

Rearranging:
k = log n base 2.

所以在叶节点处,我们将遍历的二叉树的高度将是 log(n) base 2。在我们的例子中,我们将搜索空间乘以 2 并以幂遍历搜索空间两个在log(n) 时间到达结束元素。

这两个循环的总时间复杂度大约为 n * log n = O(nlog(n))

【讨论】:

    【解决方案4】:

    由于内循环是

    for(j=1;j<n;j++)
    

    对于外循环的每次迭代,内循环将执行 n 次。您只需要知道外循环执行了多少次,然后将这两个值相乘即可。

    k 将采用以下值

    2^0, 2^1, 2^2, ...., 2^i where 2^i < n
    

    取不等式两边的对数(以2为底)

         2^i < n
    log(2^i) < log(n)
    i*log(2) < log(n)
           i < log(n)
    

    外层循环将精确执行 i + 1 次,因此复杂度为 O(i*n),但从上面看,i

    如果相反,内部循环是

    for(j=1;j<k;j++)
    

    然后内部循环会执行

    2^0 + 2^1 + ... + 2^i 
    

    注意这是一个系列而不是一个序列。事实上,它是众所周知的geometric series。该系列的总和由下式给出

    a(1 - r^(i + 1))/(1 - r) 
    

    其中 a = 1,r = 2,如果你用 log(n) 代替 i(它是之前分析的 log(n)),你会得到

    2^(log(n) + 1) - 1
    

    这是

    2*n - 1
    

    【讨论】:

    • 哦。 k...但是如果我不通过记录来推断它怎么办。因为我不会知道。如果我写为 timecoplexity = O(n*(2^i)) 是否正确
    • 不,这将使它成为 O(n^2)。我已经更新了可读性的推理。
    • 哦...非常感谢您的解释
    • 这个的时间复杂度是多少: for(k=1;k
    • 谢谢,但仍有疑问。你为什么用 i 代替登录
    猜你喜欢
    • 1970-01-01
    • 2011-08-17
    • 2016-04-07
    • 2022-11-05
    • 1970-01-01
    • 1970-01-01
    • 2013-09-26
    • 1970-01-01
    相关资源
    最近更新 更多