【问题标题】:Why the time complexity is different even when I am using only one loop?为什么即使我只使用一个循环,时间复杂度也会不同?
【发布时间】:2018-12-28 22:02:35
【问题描述】:

我正在解决 CodeLab 上的一个问题,该问题要求在适当的位置删除重复项,以便每个元素最多可以出现两次并返回新的长度。

给定输入数组 A = [1,1,1,2] 您的函数应该返回长度 = 3,而 A 现在是 [1,1,2]

我的 Python 代码运行良好且正确,但运行时间(时间复杂度)太长。但是当我运行类似的 Java 代码(一个循环)时,它会接受它。我在 Python 代码中做错了什么以至于时间太多了?

def removeDuplicates(A):
    if len(A) <= 2:
        return len(A)
    i = 0
    n = len(A)
    while i < n:
        if i <= len(A)-3:
            if A[i] == A[i+1] and A[i] == A[i+2]:
                del A[i]
                i -= 1
        i += 1
    return i

Java 代码:

public int removeDuplicates(ArrayList<Integer> a) {
    int count = 1;
    int shiftLeft = 0;
    int i = 1;
    while (i < a.size()){
        a.set(i-shiftLeft, a.get(i));
        if (a.get(i-1-shiftLeft).equals(a.get(i))){
            count ++;
        }
        else {
            count = 1;
        }
        if (count == 3){
            shiftLeft ++;
            count --;
        }
        i ++;
    }
    for (int j=0; j<shiftLeft; j++){
        a.remove(a.size()-1);
    }
    return a.size();
}

【问题讨论】:

  • 请修复python格式。缩进比 Java 更重要
  • 只是猜测:del A[i] 的复杂度为 O(n-i)。在 Java 中,您只需调用 a.remove(a.size()-1) 即可删除最后一个元素。 (大约 O(1))。
  • 我不明白 python 代码是如何工作的。您不会在循环中重新计算 n。这肯定会引发索引错误?
  • @MichaelButscher 谢谢迈克尔。但是由于索引(i)处的指针,它仍然需要O(n-1)吗?
  • del A[i] 必须将所有列表元素从i 之后的一个索引向后移动到最后一个索引。在 Python 中,这些元素只是指针(也称为引用),但复杂性仍然是线性的。

标签: python python-3.x performance time-complexity


【解决方案1】:

从给定索引的数组中删除需要线性时间。那是因为您必须将其右侧的所有元素向左移动一个空格,这也需要 O(n)。

您可以使用以下技巧在恒定时间内自行删除。首先将要删除的元素交换到数组的末尾,然后使用pop() 将数组大小减少一个元素。

你无法实现这样的通用删除,因为即使数组没有排序,它仍然可能有一些需要保留的特定顺序。


回到问题:你得到了一个约束,你必须就地实现它,没有额外的空间,只有一个循环。也就是说,这是我现在能想到的最好的:

l = [1, 2, 3, 4, 4, 4, 4, 5, 5, 5, 6]

def removeDuplicates(l):
    for i in range(len(l) - 1, 0, -1): 
        if (l[:i]).count(l[i]) >= 2:
            del l[i]
    return(l)

print(removeDuplicates(A)) #=> 8
print(l) #=> [1, 2, 3, 4, 4, 5, 5, 6]

【讨论】:

  • 谢谢。这是一个很好的技巧。但是如果我想删除多个(比如 4 或 5 个元素),那么如何继续交换所有元素呢?请您提供一小段代码
  • 你可以使用set()吗?
  • Set() 将删除所有重复项。我应该最多允许每个重复项中的 2 个。
  • @anyanya 使用dict 计数
  • @juanpa.arrivillaga 我必须在没有任何额外空间的情况下执行此操作,只有一个循环
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-24
  • 1970-01-01
  • 2018-01-14
  • 2020-09-10
  • 2015-09-07
相关资源
最近更新 更多