涉及两个for循环的算法的时间复杂度

问题描述

public static void main(String[] args) {

  Scanner sc = new Scanner(system.in);

  int n = sc.nextInt();
  int m = sc.nextInt();
  int result = 0;

  for (int i=0; i < n; i++) {
    for (int j=m; j > 0; j--)
      result += 1;
    m -= 1;

  }
  System.out.println(result);
}

问题是对还是错的问题。该语句是“当n远大于2 m时,以下程序的时间复杂度为O(n m)”。对还是错?

问题中的时间复杂度是指最坏情况下的时间复杂度。这是我到目前为止所做的:

内部循环运行m次,每次m的值减小1。这样,内部循环的迭代总数为:m + m-1 + m-2 + m-3 + .... + 3 + 2 +1。

我们可以认为这是一个算术序列。

然后,内部循环的迭代总数为:m(m +1)/ 2 =(m 2 + m)/ 2。

m达到0后,由于n远远大于2 * m,因此外循环将继续以O(1)时间运行n-m倍。

因此,时间复杂度为:(m 2 + m)/ 2 + n-m = O(m 2 )。

这是解决这个问题的正确方法吗?

解决方法

不,那是不正确的。首先,这里没有“最坏情况”或“最好情况”,因为步数完全由nm决定。

正如您所说,问题是是/否。因此,简单地计算时间复杂度并不是解决此问题的正确方法(顺便说一句,结果不是 O(m^2)-您不能只丢弃n!)。

您的推理直到最后一步都是正确的。如您正确计算的那样,步数为(m^2 - m)/2 + n(简化后)。问题是:在(m^2 - m)/2 + n的假设下,O(mn)是集合n >> 2m的成员吗?

为简单起见,忽略常量,让我们将假设记为不等式:

(m^2 - m)/2 + n < nm (eventually,as n,m grow)

现在两边除以nm会产生相等的不等式

(m - 1)/(2n) + 1/m < 1

根据这个假设,第一项消失了,所以我们剩下1/m < 1,这显然是正确的,随着m的增长。因此,假设是正确的,而答案是肯定的