【问题标题】:Better understanding of (log n) time complexity更好地理解 (log n) 时间复杂度
【发布时间】:2019-01-14 22:46:26
【问题描述】:

我对 (log n) 有点困惑。鉴于此代码

public static boolean IsPalindrome(String s) {
    char[] chars = s.toCharArray();
    for (int i = 0; i < (chars.length / 2); i++) {
        if (chars[i] != chars[(chars.length - i - 1)])
            return false;
        }
        return true;
    }
}

我正在循环 n/2 次。因此,随着 n 长度的增加,我的时间增加了 n 时间的一半。在我看来,我认为这正是 log n 是什么?但是写这段代码的人说这仍然是O(N)。

在什么情况下循环,可以是(log n)吗?例如这段代码:

1. for (int i = 0; i < (n * .8); i++)

这是日志吗?我正在循环 n 长度的 80%。

这个呢?

2. for (int i = 1; i < n; i += (i * 1.2))

那是日志 n 吗?如果是这样,为什么。

【问题讨论】:

  • 最后是一个O(log n)。 (1) 只是 O(n).
  • 时间复杂度通常是关于输入的大小,这里对于一个大小为 n 的字符串需要 O(n) 操作,所以复杂度是 O(n),你说的是就像不同的增长一样,最后一个是 log(n) 因为它需要 log_1.2(n) 次左右的操作才能通过循环,这(假设循环体没有太多操作)实现了复杂性是 O(log(n))
  • 你熟悉对数吗?
  • O(n/2) 与 O(n) 相同,但日志完全不同。例如,以 10 为底的日志告诉您该数字中有多少位: log(1) = 0, log(10) = 1, log(100) = 2, log(10000000000) = 10 所以你看到O(log(n)) 算法,如果你循环 100 次你可以处理一个谷歌项目 (10^100),这与划分非常不同。
  • 复杂度只是简单地定义操作变化的数量与条目元素的数量相比。第一个例子是字符数和循环数之间的线性关系(图上的一条线)。在最后一个示例中,for 循环上的步长间隔每步增加 20%,这意味着随着时间的推移,步长会变大,因此步数会以指数方式减少,因此会产生对数复杂度。所以你可以有两种算法 O(n) 但一个循环 n/2 次,第二个循环 n/4 次。

标签: algorithm performance time-complexity big-o


【解决方案1】:

1. for (int i = 0; i &lt; (n * .8); i++) 在第一种情况下,基本上你可以用另一个变量替换 0.8n,我们称之为 m。

for (int i = 0; i &lt; m; i++) 你循环了 m​​ 次。您在每次迭代中将 i 的值增加一个单位。由于mn只是变量名,所以上述循环的Big-O复杂度为O(n)。

2. for (int i = 0; i &lt; n; i += (i * 1.2)) 在第二种情况下,您没有增加i 的值,i 的值始终是0。这是一个for-infinite循环的经典案例。

您正在寻找的是2. for (int i = 1; i &lt;= n; i += (i * 1.2)) 在这里,您正在以对数方式递增 i 的值(但不是以 2 为底)。

考虑for (int i = 1; i &lt;= n; i += i) 每次迭代后 i 的值加倍。 i 的值将是 1, 2, 4, 8, 16, 32, 64.. 假设 n 值为 64,您的循环将在 7 次迭代中终止,即 (log(64) to the base 2) + 1(+1,因为我们从 1) 个操作数开始循环。因此它变成了对数运算。

2. for (int i = 1; i &lt;= n; i += (i * 1.2)) 在您的情况下,解决方案也是对数解决方案,但它不是以 2 为底的。您的对数运算的底是 2.2,但在大 O 表示法中,它归结为 @ 987654337@

【讨论】:

    【解决方案2】:

    我想你想念什么是 time complexity 以及 big O notation 的工作原理。

    Big O 表示法用于将算法的渐近行为描述为问题增长的大小(到无穷大)。特定的系数无关紧要。

    作为一个简单的直觉,如果当你将n增加2的倍数时,你需要执行的步数也增加了大约2倍,这就是线性时间复杂度或者所谓的O(n).

    让我们回到您的示例 #1 和 #2:

    1. 是的,您只执行 chars.length/2 循环迭代,但如果 s 的长度加倍,则迭代次数也加倍。这正是线性时间复杂度

    2. 与之前的情况类似,您执行 0.8*n 迭代,但如果 n 加倍,您将执行两倍的迭代。这又是线性的

    最后一个例子不同。系数1.2 并不重要。重要的是您将i 添加到自身。让我们稍微重写一下那个语句

    i += (i * 1.2)
    

    相同
    i = i + (i * 1.2)
    

    相同
    i = 2.2 * i
    

    现在您清楚地看到,每次迭代都比i 增加了一倍以上。因此,如果您将n 加倍,您只需要再进行一次迭代(甚至相同)。这是基本亚线性时间复杂度的标志。是的,这是O(log(n)) 的一个例子,因为对于一个大的n,您只需要大约log(n, base=2.2) 迭代,这是真的

     log(n, base=a) = log(n, base=b) / log(n, base=b) = constant * log(x, base=b) 
    

    constant1/log(a, base=b)

    【讨论】:

      猜你喜欢
      • 2011-07-09
      • 2019-09-13
      • 1970-01-01
      • 2015-06-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多