为什么这个O(nlogn)

时间:2014-09-09 23:55:22

标签: arrays data-structures big-o time-complexity

我今天接受了实习面试,但我无法理解这一点。

total = 0

product(int array[]) {

    if (array.length == 1) {
        return array[0]
    } else {
        product(product right side array  * product left side )
    }
}

4 个答案:

答案 0 :(得分:1)

这是O(N log N),因为复制每个值的次数是O(log N)。

想象一下,你有多个级别。在第一级,在一个阵列中有N个项目,在第二个级别中有2个阵列中的N / 2个项目,在第三个级别中有4个阵列中的N / 4个项目等等,直到N个阵列中有1个项目。这需要log2(n)级别从上到下。每个值都被复制了log2(N)次,这意味着时间复杂度为O(log(N)* N),因为日志的基数并不重要。

您可能会说*new Array等其他操作更为昂贵,但这些操作都是O(N),而N只会增加更高级别的订单。

答案 1 :(得分:0)

product(left side) * product(right side)将返回一个数字,因此对product的外部调用将采用O(1)。

两个内部调用只是执行二叉树深度优先遍历数组,这需要花费O(n)时间。

然而,在步行的每个级别,它正在对product进行外部调用,并且存在O(logn)级别,并且在每个级别上,成本为O(1),因此乘以工作量通过O(logn),你得到O(nlogn)。

答案 2 :(得分:0)

原因是当数组长度为1时,时间是常数,如果长度为n,则使用2次递归调用,使用数组的一半。

更正式一点,在阵列的长度n上使用感应。在基本情况下,小数组的数组是1,显然操作数是常数(这匹配O(nlog n)......和所有内容)。

在一般归纳的情况下,如果数组长度为n,则递归调用product right side arrayproduct left side都涉及n / 2个元素(将数组分为2个部分),因此数量为操作是

n / 2(log n / 2)+ n / 2(log_2 n / 2)= n / 2(log n -1)+ n / 2(log n -1)= n log n -2。

在这种情况下,if操作计为1个附加操作,而product *本身作为一个操作,总计n log n,但添加常量不相关。

您还可以认为递归调用product(product right side array * product left side )具有log n的“深度”(在以256开头的情况下,递归调用的“深度”将为8),因为每次数组的大小是初始数组的一半。由于最后返回n个元素,因此得到O(n log(n))

答案 3 :(得分:0)

递归树的高度最多为 log_2 n ,因为这是在到达 n = 1之前可以将 n 减半的次数(即叶子节点) - 将 log_2 n 视为 n 中的位数。

树的每个级别的宽度最多为 n (在底部,每个数组元素只访问一次;树的上层显然是窄)。

在每个分支处,执行一个恒定时间( O(1))乘法运算(假设,对于此参数,该数组拆分是恒定时间)。

因此,操作数的上限是 O(1)x n x log_2 n = O(n log n)