我今天接受了实习面试,但我无法理解这一点。
total = 0
product(int array[]) {
if (array.length == 1) {
return array[0]
} else {
product(product right side array * product left side )
}
}
答案 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 array
和product 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)。