在线测试中的算法复杂度

时间:2016-09-30 17:51:01

标签: c# asymptotic-complexity

我必须完成实习的在线编程测试,并得到关于复杂性分析的问题。我回答了这个问题并且标记为错误,我只想了解原因,所以我可以改进。

问题:

  

当reverseOrder为true且为false时,给出以下算法的复杂性:

List<int> stackToList(Stack<int> stack, bool reverseOrder) {
    List<int> items = new List<int>();

    while (stack.Count > 0) {
        int item = stack.Pop();

        if (reverseOrder) {
            items.Insert(0, item);
        } else {
            items.Add(item);
        }
    }

    return items;
}

编辑:这是多项选择,可能的答案是:

  • O(1)
  • O(nlogn)
  • O(n)的
  • 为O(n ^ 2)

您可以在reverseOrder为true时选择一个,为false时选择另一个。

我的回答:

  • 当reverseOrder为真时:O(n 2
  • 当reverseOrder为false时:O(n 2

我通过以下方式得到了这个答案:

  • while循环将迭代n次,因为它会继续,直到没有元素可以弹出
  • Pop()O(1)
  • 如果reverseOrdertrue,则会在列表的前面生成Insert。由于List<T>由数组支持,因此会动态调整大小,并将每个元素向上移动一个空格,并将元素插入索引0.根据https://msdn.microsoft.com/en-us/library/sey5k5z4(v=vs.110).aspx

      

    此方法是O(n)操作,其中n是Count。

  • 如果reverseOrderfalse,则Add会将项目附加到列表的后面。由于items没有给出初始尺寸,Count永远不会小于Capacity,导致调整大小,因此根据https://msdn.microsoft.com/en-us/library/3wcytfd1(v=vs.110).aspx

      

    如果Count小于Capacity,则此方法为O(1)操作。如果需要增加容量以容纳新元素,则此方法将成为O(n)操作,其中n为Count。

此刻我感到非常沮丧,因为这个错误导致我的分数直线下降,即使我在测试中得到了所有其他问题也是正确的。

4 个答案:

答案 0 :(得分:4)

您需要询问编写测试的人员。这里的任何答案都是严格意见的,因为我们没有完整的上下文,即什么会导致测试作者以不同的方式描述算法的复杂性。

那就是说,我会同意reverseOrder == false场景中的测试作者。虽然在调用Add()期间可能可能招致调整大小操作,但调整大小操作会在最坏情况下引入log N成本,因为每个调整大小时新大小会加倍

你没有说出正确答案应该是什么,但我会把它作为O(N log N)。

答案 1 :(得分:1)

您的假设是每次添加项目时容量都会增加 - 这是不正确的。文档似乎没有提到确切的算法,但我相信每次容量增加时它都会翻倍。您可以在关于您链接的文档中的恐龙样本中看到它们 - 它们添加了5个恐龙,容量报告为8个。

答案 2 :(得分:0)

查看

的第6669行

http://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,cf7f4095e4de7646

很明显,在列表的开头插入会强制复制到列表的所有位置。所以每个插入都需要N次移动。 O(N ^ 2)它在我看来。

答案 3 :(得分:0)

stackToList(stack, true )= O(n)。大多数情况下,这个调用将是O(1)。但是,当List.Add函数必须扩展超过其容量时,需要将该数组复制到容量是之前两倍的新数组,并迭代前面的项目以将它们存储在新数组中。因此,我们可以将excel中的实际操作表示为IF(n LOG(n,2)(n / 2)/ INT(n LOG(n,2) (n / 2))= 1,n,1)。如果没有资源瓶颈,如果这个算法在10秒内完成1000万项,那么完成1亿个项目就可能需要大约10(10)秒。实际上,我们知道它会比Big O Notation预测稍差,因为O(n)操作将需要很多O(1)操作才能从中恢复。

放大后,您可以看到List.Copy()如何影响累积操作 First 65 n by Cumulative Operation Count

缩小,你可以看到它与O(n)操作相比并没有真正影响比例。 First 650 n by Cumulative Operation Count

stackToList(stack, false )= O(n ^ 2)。列表的insert函数执行数组副本,该副本必须将列表中的所有元素移动到新列表。当指针开始迭代通过父堆栈时,操作数从0开始,然后增长直到达到n。平均而言,它发生n / 2次。常量2在Big O表示法中删除,你留下n。如果没有资源瓶颈,如果这个算法在10秒内完成了1000万个项目,要完成1亿个项目,你可能需要大约10(10 ^ 2)秒。实际上,我们知道第二种情况比Big O Notation预测更好,因为它实际上是n *(n-1),但它不会比O(n * Log(n))更好地扩展,下一步下。 Descending Operation Comparison

分解运营:

List<int> stackToList(Stack<int> stack, bool reverseOrder) {
    List<int> items = new List<int>(); // O(1)

    while (stack.Count > 0) {        //  O(n): For every int in the supplied stack
        int item = stack.Pop();        // O(1): https://referencesource.microsoft.com/#System/compmod/system/collections/generic/stack.cs,222

        if (reverseOrder) {            // O(1)
            items.Insert(0, item);     // O(n^2): https://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,669
        } else {
            items.Add(item);           // O(Slightly more than 1): https://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,220
        }
    }
    return items;
}