您如何确定此算法的平均情况复杂度?

时间:2017-11-26 16:06:46

标签: algorithm math random time-complexity big-o

通常很容易计算最佳情况和最坏情况下的时间复杂度,但是当涉及到平均情况时,尤其是在给出概率p的情况下,我不知道从哪里开始。

让我们看看以下算法来计算矩阵中所有元素的乘积:

int computeProduct(int[][] A, int m, int n) {
    int product = 1;
    for (int i = 0; i < m; i++ {
        for (int j = 0; j < n; j++) {
            if (A[i][j] == 0) return 0;
            product = product * A[i][j];
        }
    }
    return product;
}

假设p是A[i][j]为0的概率(即算法在那里终止,返回0);我们如何推导出该算法的平均时间复杂度?

1 个答案:

答案 0 :(得分:3)

让我们考虑一个相关的问题。想象一下,你有一枚硬币以概率p翻转头部。多少次,在期待中,你需要在它出现之前翻转硬币吗?答案是1 / p,因为

  • 你有可能需要一次翻转。
  • 有一个p(1-p)的机会,你需要两次翻转(第一次翻转必须去尾巴,第二次必须去头)。
  • 有一个p(1-p)^ 2的机会,你需要三次翻转(前两次翻转需要尾巴,第三次必须去头)
  • ...
  • 有一个p(1-p)^(k-1)的机会,你需要k翻转(第一个k-1翻转需要去尾巴,​​而kth需要去头。)

所以这意味着翻转次数的预期值是

  

p + 2p(1 - p)+ 3p(1 - p)^ 2 + 4p(1 - p)^ 3 + ...

     

= p(1(1 - p)^ 0 + 2(1 - p)^ 1 + 3(1 - p)^ 2 + ...)

所以现在我们需要弄清楚这个总结是什么。一般形式是

  

p从k = 1到无穷大(k(1 - p)^ k)。

不要解决这个特定的总和,而是让它更通用。设x是一个变量,稍后我们将设置为1 - p,但现在我们将其视为自由值。然后我们可以将上述求和重写为

  

p从k = 1到无穷大(kx ^(k-1))。

现在有一个可爱的技巧:注意这个表达式的内部是x ^ k相对于x的导数。因此,这个总和是

  

p从k = 1到无穷大(d / dx x ^ k)。

导数是一个线性算子,所以我们可以把它移到前面:

  

p d / dx和从k = 1到无穷大(x ^ k)

内部和(x + x ^ 2 + x ^ 3 + ...)是1 /(1 - x) - 1的泰勒级数,所以我们可以简化这个以得到

  

p d / dx(1 /(1 - x) - 1)

     

= p /(1 - x)^ 2

由于我们选择了x = 1 - p,这简化为

  

(1 - (1 - p))^ 2

     

= p / p ^ 2

     

= 1 / p

呼!这是一个很长的推导。但它表明所需的投币数量为1 / p。

现在,在你的情况下,你的算法可以被认为是投掷mn硬币,它们以概率p出现并且如果它们中的任何一个出现就停止。当然,您需要投掷的预期硬币数量不会超过您允许无限次翻转的情况,因此您的预期运行时间最多为O(1 / p)(假设p> 0) )。

如果我们假设p与m和n无关,那么我们可以注意到,在一些初始增长之后,随着我们增加翻转次数,每次添加的项加入到我们的总和中的指数低于前一次。更具体地说,在大致以对数方式将多个项加入到总和之后,在无限求和的情况下,我们将从总数中删除。因此,假设mn大致大于Θ(log p),则总和最终为Θ(1 / p)。因此,在大O意义上,如果mn独立于p,则运行时为Θ(1 / p)。