【问题标题】:Java - Time Complexity O(N**2)Java - 时间复杂度 O(N**2)
【发布时间】:2022-01-20 13:26:26
【问题描述】:

我正在练习 Codility。有一个简单级别的问题,但我被困在性能上。测试结果分析将此代码标记为O(N**2),但显然没有任何嵌套循环。谁能告诉我为什么我的代码是 O(N**2)?

public static int solution(int X, int[] A) {
    List<Integer> temp = new ArrayList<>();
    for (int i = 1; i <= X; i++ ){
        temp.add(i);
    }

    int counter = 0;
    int res = -1;
    for (int i: A){
        if (temp.contains(i)) {
            temp.remove(new Integer(i));
        }
        if (temp.size() == 0){
            res= counter;
            break;
        }
        counter++;
    }

    if (temp.size() != 0){

        res = -1;
    }
    return res;
}

【问题讨论】:

  • 您可能需要检查documentation for ArrayList:“[add 除外,所有其他操作都以线性时间运行(粗略地说)”您已致电 containsremove循环中。
  • 我认为这是由于使用了removecontains。在最坏的情况下,它们将花费整个数组的遍历。

标签: java time-complexity


【解决方案1】:

那是因为使用了containstempArrayListcontains 执行线性查找。在 for 循环中,这将变为 O(N2)

【讨论】:

  • 这个结论取决于Xtemp的初始长度,保证与A.length成正比。如果没有这样的约束,渐近复杂度可能或多或少,我们可以肯定地说是 O(X * N)。
【解决方案2】:

测试结果分析将此代码标记为O(N**2),但显然 没有任何嵌套循环。谁能告诉我为什么我的代码是 O(N**2)?

渐近复杂度不(仅)与循环计数有关。您对A 的元素有一个循环,并在其中调用temp.contains(),并有条件地调用temp.remove()。对于ArrayList,每一项的成本都与temp 中的元素数量成正比。

总体而言,如果NA.length,那么您的方法的渐近复杂度为 O(X * N)。 Codility 的分析似乎不太正确,但如果不能将X 视为由常数限制,那么您的代码仍然比O(N) 更复杂。如果 Codility 执行启发式分析,在 XN 之间引入人为关系,然后服从该函数关系,您的方法确实可能是 O(N2 )。


你绝对可以做得更好。您的方法似乎是计算 A 的最小初始子数组的长度,该子数组包含 1 和 X 之间的所有整数。为了有效地执行此操作,您确实需要某种机制来跟踪已看到的值,但包含在 List 中是一个昂贵的选择。请考虑使用 boolean 的数组来跟踪已看到哪些特定值,并单独计算已看到的数量:

boolean[] seen = new boolean[X + 1];
int numSeen = 0;

有了这个,循环遍历A 的元素,并且对于在1 ... X 范围内的每个元素i,测试seen[i](每次测试花费O(1))。如果true,什么也不做。如果false,将seen[i]设置为true(O(1)),递增numSeen(O(1)),并测试numSeen是否达到X(O(1))。返回在numSeen 达到X 之前必须检查的元素数,如果numSeen 从未达到X,则返回-1。 (细节留作练习。)

这样,每次循环迭代都会执行O(1) 工作,而不管X 上的任何限制,而O(1) 工作实际上是便宜,这是一个不同的考虑因素。总体而言:O(N),效率也很高。

【讨论】:

    【解决方案3】:

    另一个循环隐藏在ArrayList的remove方法中。 ArrayList的remove方法是O(N),因为它必须移动元素来填补空白。

    for (int i: A){   // ===> O(N)
            if (temp.contains(i)) {
                temp.remove(new Integer(i));  //===> O(N)
            }
            if (temp.size() == 0){
                res= counter;
                break;
            }
            counter++;
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-12-09
      • 1970-01-01
      • 1970-01-01
      • 2021-04-14
      • 2015-05-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多