大 O - O(log(n)) 代码示例

Posted

技术标签:

【中文标题】大 O - O(log(n)) 代码示例【英文标题】:Big O - O(log(n)) code example 【发布时间】:2013-06-11 22:45:24 【问题描述】:

就像大 O 符号“O(1)”可以描述以下代码:

O(1):

    for (int i = 0; i < 10; i++) 
        // do stuff 
        a[i] = INT;
    

O(n):

    for (int i = 0; i < n; i++) 
        // do stuff 
        a[i] = INT;
    

O(n^2):
    for (int i = 0; i < n; i++) 
        for (int j = 0; j < n; j++) 
            // do stuff
            a[i][j] = INT;
        
    
O(log(n)) 可以描述什么代码?

另一个问题:

对于“大 O 问题”(当获取大量数据作为输入时该怎么办)有哪些解决方案?

【问题讨论】:

O(log n) 通常是在算法分而治之的时候,比如二分搜索或类似的。 这是一个实用的(编码测试)示例leetcode.com/problems/find-peak-element => 查看问题和解决方案 【参考方案1】:

经典例子:

while (x > 0)   
   x /= 2;  
  

这将是:

Iteration |   x
----------+-------
    0     |   x
    1     |  x/2
    2     |  x/4
   ...    |  ...
   ...    |  ...
    k     |  x/2^k 

2k = x → 两边应用对数 → k = log(x)

【讨论】:

伟大而简单的例子,正是我想要的!谢谢你:) 我错过了你得到 2^k = x 的那一刻,而它曾经是 x/2^k ? 1 是最后一次迭代。所以我想知道在哪一点上这将被评估为 1。 有史以来最好的解释。非常感谢。 @DanielGurinov,x/2^k 的除法最终会得到 1。等式这会给你, 1=x/2^k ,相当于, x=2^k ,关于应用日志。当 b 的 y 次方等于 x 时: b^y = x ;在这种情况下 2^y=x 那么 x 的以 b 为底的对数等于 y: logb(x) = y ;在这种情况下,k = log(x) 意味着 log base 2【参考方案2】:

带有 for 循环的最简单代码,可用于表示:

O(1):

function O_1(i) 
    // console.log(i);
    return 1

O(n):

function O_N(n) 
    count = 0;
    for (i = 0; i < n; i++) 
        // console.log(i);
        count++;
    
    return count

O(n²):

function O_N2(n) 
    count = 0;
    for (i = 0; i < n; i++) 
        for (j = 0; j < n; j++) 
            // console.log(i, j);
            count++;
        
    
    return count

O(Log2(n)):

function O_LOG_2(n) 
    count = 0;
    for (var i = 1; i < n; i = i * 2) 

        count++;
    
    return count

O(Sqrt(n)):

function O_SQRT(n) 
    count = 0;
    for (var i = 1; i * i < n; i++) 
        // console.log(i);
        count++;
    
    return count

【讨论】:

【参考方案3】:

根据定义,log(n)(我的意思是以 2 为底的对数,但底数实际上并不重要)是您必须乘以 2 才能得到 n 的次数。所以,O(log(n)) 代码示例是:

i = 1
while(i < n)
    i = i * 2
    // maybe doing addition O(1) code

在实际代码示例中,您可以在二进制搜索、平衡二进制搜索树、许多递归算法、优先级队列中遇到 O(log(n))。

【讨论】:

【参考方案4】:

对于 O(logn),请查看任何涉及分治策略的代码 示例:合并排序和快速排序(在这些情况下,预计运行时间为 O(nlogn))

【讨论】:

【参考方案5】:

二分搜索是一个例子 O(log(n))。 http://en.wikipedia.org/wiki/Binary_search_algorithm.

【讨论】:

【参考方案6】:

可能值得强调的是,您描述的较低复杂度算法是较高复杂度算法的子集。换句话说,

for (int i = 0; i < 10; i++) 
    // do stuff 
    a[i] = INT;

在 O(1) 中,但也在 O(n)、O(n²) 中,如果你想聪明一点,O(log(n))。为什么?因为所有的恒定时间算法都受到一些线性、二次等函数的限制。

对于“大 O 问题”有哪些解决方案(当获取大量数据作为输入时该怎么做)?

这个问题对我来说没有多大意义。 “大量数据”是相当随意的。不过,请记住,大 O 并不是时间复杂度的唯一衡量标准。除了测量最坏情况的时间复杂度外,我们还可以检查最佳情况和平均情况,尽管计算起来可能有点棘手。

【讨论】:

【参考方案7】:

在二分搜索的情况下,您试图找到最大的迭代次数,因此搜索空间可以分成两半的最大次数。这是通过重复将搜索空间的大小 n 除以 2 直到达到 1 来实现的。

让我们给出标签 x 需要将 n 除以 2 的次数。由于除以 2,x 次等于除以 2^x,因此您最终必须求解这个等式:

n/2^x = 1,变成n = 2^x,

所以使用对数,x = log(n),所以二进制搜索的 BIG - O 是 O(log(n))

重申一下:x 是在将大小为 n 的空间缩小到大小为 1 之前,您可以将其分成两半的次数。

http://www.quora.com/How-would-you-explain-O-log-n-in-algorithms-to-1st-year-undergrad-student

【讨论】:

以上是关于大 O - O(log(n)) 代码示例的主要内容,如果未能解决你的问题,请参考以下文章

为啥代码的时间复杂度为 O(log n)?

是否会以O(n ^ 2)复杂度运行循环中的变量?

p78 3的幂 (leetcode 326)

p122 合并 K 个有序链表(leetcode 23)

二分法查找

二分法查找