嵌套的for循环是否自动为O(n ^ 2)?

时间:2019-05-15 10:33:50

标签: time-complexity

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

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

执行此嵌套的for循环以检查行。再次执行以检查列。再为子方块多做一个,但又一个更时髦,因为我们将数独板划分为多个子板,因此最终导致了两个以上的嵌套循环,也许是三个或四个。

后来我被问到这段代码的复杂性。坦白说,就我而言,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)
        // ...

2 个答案:

答案 0 :(得分:1)

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

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

当你说类似的话

  

对板子的所有单元格进行了3次精确访问,所以O(3n)。

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


关于标题中的问题(自动嵌套嵌套的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)


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


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

答案 1 :(得分:0)

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

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

但是,如果您说的话,网格总数为N(即,板号为sqrt(N)-by-sqrt(N)),那么复杂度为O(N),如果您是3O(N)介意常数。