【问题标题】:Is a nested for loop automatically O(n^2)?嵌套for循环是否自动O(n ^ 2)?
【发布时间】:2019-10-02 11:22:32
【问题描述】:

我最近被问到一个关于测试数独板有效性的面试问题。基本答案涉及for 循环。本质上:

for(int x = 0; x != 9; ++x)    
    for(int y = 0; y != 9; ++y)
        // ...

执行这个嵌套的for 循环来检查行。再次执行以检查列。为子方块再做一个,但那个更时髦,因为我们将 suoku 板划分为子板,所以我们最终会得到两个以上的嵌套循环,可能是三个或四个。

后来有人问我这段代码的复杂性。坦率地说,就我而言,董事会的所有单元都被访问了三遍,所以O(3n)。对我来说,我们有嵌套循环这一事实并不意味着这段代码自动成为O(n^2)even O(n^highest-nesting-level-of-loops)。但我怀疑这就是面试官所期望的答案......

换个说法,这两段代码的复杂度是多少:

for(int i = 0; i != n; ++i)
    // ...

和:

for(int i = 0; i != sqrt(n); ++i)
    for(int j = 0; j != sqrt(n); ++j)
        // ...

【问题讨论】:

    标签: time-complexity


    【解决方案1】:

    您的一般直觉是正确的。让我们澄清一下 Big-O 表示法:

    Big-O 为您的算法的最坏情况(时间)复杂度提供了一个上限,与 n(输入的大小)相关。本质上,它是衡量工作量如何随输入大小变化的指标。

    当你说类似的话

    棋盘的所有单元格都被访问了 3 次,所以 O(3n)。

    您的意思是 n(您的输入的大小)是 板中单元格的数量,因此访问所有单元格三次确实是 O(3n)(其中是 O(n)) 操作。如果是这种情况,您将是正确的。
    然而,通常当提到数独问题(或涉及一般网格的问题)时,n 被认为是每行/列中的单元格数(n x n 板)。在这种情况下,运行时复杂度将为 O(3n²)(实际上等于 O(n²))。
    将来,问面试官 n 是什么是完全有效的。


    至于标题中的问题(嵌套的 for 循环是否自动 O(n^2)?)简短的回答是否
    考虑这个例子:

    for(int i = 0 ; i < n ; i++) {
        for(int j = 0 ; j < n ; j * 2) {
           ... // some constant time operation
        }
    }
    

    外部循环进行 n 次迭代,而内部循环进行 log2(n) 次迭代 - 因此时间复杂度将为 O(nlogn).


    在您的示例中,在第一个示例中,您有一个进行 n 次迭代的 for 循环,因此(至少)O(n) 的复杂性(操作执行 n 的顺序次)。
    在第二个中,你有两个嵌套的 for 循环,每个循环都进行 sqrt(n) 迭代,因此总运行时复杂度也为(至少)O(n)。第二个函数不会自动为 O(n^2),因为它包含一个嵌套循环。正在执行的操作量仍然是相同的顺序 (n),因此这两个示例具有相同的复杂性 - 因为我们假设两个示例的 n 相同
    这是启航回家的最关键点。要比较两种算法的性能,您必须使用相同的输入进行比较。在您的数独问题中,您可以用几种不同的方式定义n,而您所做的方式将直接影响问题的复杂性计算——即使工作量相同。


    *注意 - 这与您的问题无关,但将来避免在循环条件中使用 !=。在第二个示例中,如果 log(n) 不是整数,则循环可能会永远运行,具体取决于语言及其定义方式。因此建议改用&lt;

    【讨论】:

    • 感谢您的回答。尽管如此,我还是忍不住觉得使用两个循环来限定循环内存是很奇怪/愚蠢/不诚实的 n^2 因为碰巧我们对内存的心理表征是一个方形的游戏板......我可以迭代在二维数组int a[10][10] 上使用单个循环:for(int i = 0; i != 100; ++i){ a[i / 10][i % 10];}。这是否突然使我的算法从O(n^2) 变为O(n)?我正在做完全相同的工作!
    • 同样,这仅取决于您如何定义输入 n。当您首先考虑使用 Big-O 的动机时,它会变得更加清晰:当我们查看编码问题和一些解决方案时,我们想知道我们的解决方案时间对于更大的输入增加的速率。换句话说:它是如何扩展的。在您的示例中,如果您定义 n =10^2,您可以说您的算法是 O(n),但它与将 n 定义为 10 并称其为 O(n^2) 有何不同? 对于常见问题,n 以特定方式定义为惯例,以使讨论更容易和更有成效。
    【解决方案2】:

    这取决于你如何定义所谓的N

    如果棋盘的大小是N×N,那么是的,复杂度是O(N^2)。

    但是如果你说,网格的总数是 N(即 board id sqrt(N)-by-sqrt(N)),那么复杂度是 O(N),如果你是 3O(N)注意常数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-05-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-03
      • 1970-01-01
      • 2015-07-29
      • 1970-01-01
      相关资源
      最近更新 更多