各种搜索算法的大O运行时间

时间:2012-10-01 03:36:02

标签: java big-o code-analysis asymptotic-complexity

如果hasTwoTrueValues数组中至少有两个值为true,则方法boolean会返回true。为所提出的所有三种实现提供Big-O运行时间。

// 版本1

public boolean hasTwoTrueValues(boolean[] arr) {
    int count = 0;
    for(int i = 0; i < arr.length; i++)
        if(arr[i])
            count++;
        return count >= 2;
}

// 版本2

public boolean hasTwoTrueValues(boolean[] arr) {
    for(int i = 0; i < arr.length; i++)
        for(int j = i + 1; j < arr.length; j++ )
            if(arr[i] && arr[j])
                return true;
}

// 版本3

public boolean hasTwoTrueValues(boolean[] arr) {
    for(int i = 0; i < arr.length; i++)
        if(arr[i])
            for(int j = i + 1; j < arr.length; j++)
                if(arr[j])
                    return true;
                        return false;
}

这些是我的答案:

  • 版本1 O(n)
  • 版本2 O(n^2)
  • 版本3 O(n^2)

我对这个Big-O符号真的很陌生,所以如果我的答案是正确/不正确,我需要指导。如果我错了,你能解释一下并帮助我学习吗?

2 个答案:

答案 0 :(得分:4)

版本1非常简单并且是线性的,因此其运行时间平均为O(n)。

版本2更有趣。它以n(n-1)平均运行,即O(n 2 )。在这个循环中有一个早期return,所以它肯定可能早在前两个元素中断。

版本3比较棘手。你必须小心这一点。仅当arr[i]true时,第二个循环才会运行。必须将它的运行时放入不同的类别中。

  • 如果数组的所有元素都为false,那么运行时将为O(n)。
  • 如果数组的一半元素为真,那么你将在(n(n-1))/ 2的条件下运行第二个循环,即O(n 2 )。
  • 如果数组的所有元素都为真,那么您将在O(n 2 )中运行。您也将在前两个元素后立即退出,但您仍然使用两个循环来执行操作。

可以肯定地说,版本3的平均最差运行时将是O(n 2 )。最好的是O(n),这绝对是可能的。

答案 1 :(得分:0)

简而言之,最坏情况运行时间是: 版本1:O(n)
版本2:O(n^2)
版本3:O(n)

<小时/> 更详细的分析......

对于此算法,您必须考虑最佳情况,最差情况和平均情况运行时才能进行有意义的比较。

对于他们每个人,以下应该举例说明:

bestCase = [ true, true, ...] // the first two are true
worstCase = [ false, false, ..., false] // all are false
averageCase = [ true, ..., true, ..., false // second true value is found about half-way

对于所有算法,最佳情况下的运行时间为O(2),意味着恒定时间。

在最坏的情况下,您的第一个算法是O(n),这意味着线性运行时。 但是,在最坏的情况下,您的第二个算法将非常具体地退化,因为在每个步骤中您只需要检查一个元素。您最终会得到总和n + (n-1) + (n-2) + ...,它将评估为n(n-1)/2,正如您所说,它位于O(n^2),并且以二次方式增长。

在所有都是假的“最坏情况”中(我们将会看到,实际上这不是版本3 的最坏情况),您的第三个算法实际上是在线性时间内运行的,因为if语句阻止第二个循环运行。

事实证明,版本3 永远不会以二次方式运行:它在平均和最差情况下都是线性的,因为它会线性扫描第一个{ {1}},然后在找到之后线性地扫描其余的true,尽管它甚至不起作用! 因为在内部for循环中有两个返回值,一旦遇到第一个true值,如果下一个直接邻居是true,它将返回true。但是,如果下一个直接邻居是true,它会立即返回false并且不会检查任何其他值。这意味着输入:

false
只要看到第二个错误值,

版本3 就会返回false。 (从技术上讲,我假设您希望在for循环中执行此[ true, false, true ] ,在这种情况下,您还需要添加return false,同样需要添加第一个版本。虽然并非总是必要,但它有助于澄清究竟发生了什么,特别是因为这与你当前的缩进不匹配。当缺席时,只有紧随其后的语句包含在循环/ if body中。)我怀疑,即使实现正确,* 版本3 仍将在输入上具有线性的更糟糕的运行时间:

{ }

第一个true将导致它在内循环中扫描[true, false, false, ..., false] 次,但是外循环将继续运行到n而不再运行内循环,总共给出2n-1个操作,当然在n

如果你的O(n)是正确的并且只是你的缩进是错误的,那么这些分析可能需要稍微修改一下,但这是你需要应用于大O问题的思维方式(一般的渐近分析。)