【问题标题】:Time complexity for an algorithm is ok?算法的时间复杂度可以吗?
【发布时间】:2017-07-09 16:02:44
【问题描述】:

我想设计一个具有O(n(log(2)n)^2) 时间复杂度的算法。我是这样写的:

for(int i=1; i<=n; i++){
 j=i;
 while(j != 1)
     j=j/2;

 j=i;
 while(j !=1)
     j=j/2;
}

它有 O(n(log(2)n)^2) 时间复杂度吗?如果没有,我哪里出错了,我该如何解决它,使其时间复杂度为O(n(log(2)n)^2)

【问题讨论】:

  • 您的算法有O(N * 2 * log N),即O(N * log N)
  • 似乎显而易见的事情是从 0 迭代到 (n*log(n))^2 的循环。
  • 您的表达式中有 3 个产品,这意味着您需要 3 个嵌套循环,第一个 O(n) 和第二个和第三个 O(log(n))
  • 另请注意,所有日志都彼此成比例,因此无需明确说明日志的基础。 O(log2(n)) = O(log(n))
  • 一个算法应该有某种输出。由于该计算的结果被丢弃,因此可以完全优化掉。因此,该算法在实践中具有 O(1) 时间复杂度。当然,因为 O(1) 包含在 O(n(log n)^2) 中,所以无论如何你已经成功了:Big-O 表示法只是复杂性的最大界限

标签: c++ time-complexity


【解决方案1】:

题外话:

正如 cmets 中的大佬所说,算法确实是O(n log n)。这恰好与将内循环的复杂度乘以外循环的结果相同,即O(log i) x O(n)

这可能会让你相信我们可以简单地添加另一个内部循环的迭代来获得(log n)2 部分:

for (int i = 1; i < n; i++) {
    int k = i;
    while (k >= 1)
        k /= 2;
        int j = i;
        while (j >= 1)
            j /= 2;
    }
}

但是让我们看看原始复杂度是如何得出的:

(使用 Sterling 近似值)

因此,建议的修改将给出:

这不是我们想要的。


我可以从最近的个人项目中想到的一个例子是半朴素的 KD-tree 构造。伪代码如下:

def kd_recursive_cons (list_points):
    if length(list_points) < predefined_threshold:
        return new leaf(list_points)

    A <- random axis (X, Y, Z)
    sort list_points by their A-coordinate

    mid <- find middle element in list_points
    list_L, list_R <- split list_points at mid

    node_L <- kd_recursive_cons(list_L)
    node_R <- kd_recursive_cons(list_R)

    return new node (node_L, node_R)
end

因此,时间复杂度函数由下式给出:

n log n 部分来自排序。我们显然可以忽略Dn 线性部分,以及常数C。因此:

这是我们想要的。


现在以相同的时间复杂度编写一段更简单的代码。我们可以利用我们在上面推导中得到的总和......

注意到传递给log函数的参数在每个循环中都被除以二,因此我们可以编写代码:

for (int i = 1; i < n; i++) {
    for (int k = n; k >= 1; k /= 2) {
        int j = k;
        while (j >= 1)
            j /= 2;
    }
}

这看起来像开头提到的“幼稚”但不正确的解决方案,不同之处在于那里的嵌套循环有不同的界限(j 不依赖于k,但k 依赖于@987654346 @ 而不是直接在n)。


编辑:一些数值测试以确认复杂性符合预期:

测试功能代码:

int T(int n) {
    int o = 0;
    for (int i = 1; i < n; i++)
        for (int j = n; j >= 1; j /= 2)
            for (int k = j; k >= 1; k /= 2, o++);
    return o;
}

数值结果:

n          T(n)
-------------------
2           3
4           18
8           70
16          225
32          651
64          1764
128         4572
256         11475
512         28105
1024        67518
2048        159666
4096        372645
8192        860055
16384       1965960
32768       4456312
65536       10026855
131072      22413141
262144      49807170
524288      110100270

然后我绘制了sqrt(T(n) / n)n。如果复杂度是正确的,这应该给出一个log(n) 图表,或者如果用对数刻度水平轴绘制,则给出一个直线

这确实是我们得到的:

【讨论】:

    猜你喜欢
    • 2017-09-25
    • 1970-01-01
    • 1970-01-01
    • 2012-05-09
    • 1970-01-01
    • 1970-01-01
    • 2013-12-31
    相关资源
    最近更新 更多