对于如何处理多个重复项或者你确切的问题不是很清楚,但我猜测你想要确保满足O(1)空间复杂度,无论时间复杂度如何,所以我会尝试回答这个问题。
使用数组,O(1)空间复杂度,O(N^2)时间复杂度:
你可以通过将重复元素交换到末尾来原地进行操作。你可以通过保持一个“当前”指针并简单地检查“下一个”元素是否与“当前”相同来找到重复元素。在最坏情况下,这需要O(n^2)时间。例如:
[1,1,2,3,4,4,5] # "cur" is index 0 (element 1), and "next" is index 1 (element 1). Swap "next" to end.
[1,2,1,3,4,4,5] # swapping
[1,2,3,1,4,4,5] # swapping
... # Tedious swapping
[1,2,3,4,4,5,1] # Done swapping. Increment "cur".
[1,2,3,4,4,5,1] # "cur" is index 1 (element 2), and "next" is index 2 (element 3). Increment "cur"
... # Boring (no duplicates detected)
[1,2,3,4,4,5,1] # "cur" is index 3 (element 4), and "next" is index 4 (element 4). Swap "next" to end.
[1,2,3,4,5,4,1] # swapping
[1,2,3,4,5,1,4] # Done swapping. Increment "cur"
... # No more duplicates
# Done
顺便提一下,在实践中,为了节省空间而牺牲时间通常是不值得的。内存很便宜,但慢的响应时间可能会失去用户,这是很昂贵的。一个值得注意的例外是嵌入式系统,其中内存可能很紧张,输入很短(在小输入上渐近运行时间不相关)。
使用链表,O(1) 空间,O(N) 时间:
如果您有一个链表而不是数组,您可以很容易地在 O(n) 时间和 O(1) 空间内完成此操作。 当你被迫“移动”元素时,链表比数组更具优势,因为它们可以移动指针而不是将所有元素移动一个位置。 cur/next 策略与上面的数组类似。以下是一个示例:
1->1->2->3->4->4->5
1
\
1->2->3->4->4->5
1->2->3->4->4->5->1
...
1->2->3->4->4->5->1
4
\
1->2->3->4->5->1
1->2->3->4->5->1->4
...
如果您可以在O(n)时间和O(1)空间内将数组转换为链表,则问题解决了。然而,这是不可能的。 链表每个元素占用的空间比数组多,因此仅通过程序中存在链表,我认为O(1)空间就会被破坏。
虽然这是一个面试问题,但指出链表更适合高效地解决此问题可能是值得的,无论问题陈述如何。通常,面试官喜欢看到您能够正确应用数据结构,有时他们也会接受输入类型的更改。
聪明的数据结构和愚蠢的代码比另一种方式要好得多。--Eric S Raymond