在常数空间和O(n)时间内找到重复条目的算法

8
给定一个包含N个整数的数组,其中只有一个整数重复。请在O(n)时间和恒定空间内找到重复的整数。整数值或N的值没有范围限制。
例如,给定一个包含6个整数的数组,如23 45 67 87 23 47。答案是23。(希望这涵盖了模糊和不明确的部分)
我在网上搜索,但未能找到任何范围未固定的类似问题。此外,这里有一个类似我的问题的示例,但他在C ++中创建了一个具有最高整数值的哈希表。但是,cpp不允许在64位计算机上创建具有2^64元素的数组。
对不起,我之前没提到过这个数组是不可变的。

14
好问题。不过你的想法或回答尚未提供。 - Alok Save
2
找到了!我能留下它吗? - Kerrek SB
5
@Constantinius: 你是说这是一个简单的问题吗?我自己找不到解决方法,也不认为有一种解决方法存在。 (翻译):@Constantinius:您是在说这是一个容易的问题吗?我个人看不到解决方案,并且我认为没有一个解决方案存在。 - interjay
“但是C++不允许在64位计算机上创建一个有2^64个元素的数组。” 你是什么意思? - BrokenGlass
1
可能是重复的问题:在O(n)时间和O(1)空间内找到重复的有符号整数 - Yakov Galka
显示剩余15条评论
8个回答

9

Jun Tarui已经证明,任何使用O(log n)空间的重复项查找器都需要至少Ω(log n / log log n)次通过,这超过了线性时间。也就是说,即使允许对数空间,你的问题也无法解决。

Gopalan和Radhakrishnan有一个有趣的算法,可以在输入上一次遍历和O((log n)^3)空间中找到重复项,这听起来是你最好的选择。

基数排序的时间复杂度为O(kn),其中k>log_2 n通常被视为一个常数,尽管是一个很大的常数。显然不能在恒定的空间中实现基数排序,但是你可以重用输入数据的空间。

如果您假设数字本身具有某些特征,则可以使用数值技巧。 如果1到n之间的几乎所有数字都存在,则只需将它们相加并减去n(n + 1)/ 2即可。 如果所有数字都是质数,则可以通过忽略除法的运行时间来作弊。

顺便说一下,对于比较排序,有一个众所周知的Ω(log_2(n!))下限,这表明谷歌可能会帮助您找到诸如查找重复项等简单问题的下限。


比较排序的下限是Ω(n log n)。请参阅《算法导论》第8章进行证明。 - Richard Povinelli
1
是的,那就是斯特林逼近公式。 - Jeff Burdges
@JeffBurdges 数组是不可变的。 - Anubhav Agarwal
1
@Jeff:没错,你说得对。我只是不习惯把它写成Ω(log_2(n!))。吃太多火鸡了,太晚了 :-) - Richard Povinelli
@Anubhav Agarwal 好的,声明 O(kn) 中的 k 常量本来就是作弊,但 Tarui 证明了没有解决方案存在,所以唯一的问题是:如何作弊?如果面试官说“常量空间”,他们可能指的是线性空间,除非你正在面试复杂性理论教授职位。 - Jeff Burdges
Tarui的论文链接无法使用。你能更新一下链接吗? - D.W.

5
如果数组未排序,则只能使用O(nlogn)进行操作。可以在这里找到一些方法。

给出的链接并没有说明如何在常量空间内完成。不能使用2^64个数字的哈希,因为C++不允许这样的内存空间。 - Anubhav Agarwal
@AnubhavAgarwal:C++肯定允许有2^64个元素的哈希表;语言中没有任何禁止这样做的内容。 - Fred Foo
@larsmans谢谢你告诉我。但我仍然希望得到一个不使用这种方法的答案。 - Anubhav Agarwal
1
@larsmans,百亿字节的DIMM仍然相当昂贵。 ;) 请参见:http://superuser.com/q/168121/97386 - Jeff Burdges

4
如果整数的范围是有限的,您可以执行一个计数排序变体,时间复杂度为O(n)。空间复杂度为O(k),其中k是整数的上界(*), 但这是一个常数,因此它是O(1)。
如果整数的范围是无限的,那么我认为没有任何方法可以做到这一点,但我不是复杂性难题的专家。
(*) 它是O(k),因为每个整数的出现次数也有一个恒定的上限,即2。

计数排序只是位向量的一般情况。 - Hot Licks
1
@HotLicks:是的,位向量就是您实现这个的方法。我太懒了,没写出算法。 - Fred Foo


2
可能最接近O(N)时间复杂度的方法可能是传统的哈希表,其中哈希条目仅是作为键使用的数字。您将遍历列表,在首先检查它是否已在表中后,将每个条目插入哈希表中。
然而,严格来说,并不是O(N),因为随着表填充,哈希搜索/插入会变得越来越慢。而且在存储方面,对于大型列表来说,它将非常昂贵——至少是数字数组大小的3倍,可能是10-20倍。

2
你的答案空间不是常数。 - Anubhav Agarwal
1
真实的。没有任何实用的算法能够完全满足规格要求。 - Hot Licks

2

正如其他人已经提到的,我看不到任何以O(n)的时间复杂度完成它的方法。

然而,您可以尝试使用概率方法,通过使用布隆过滤器。如果你很幸运,它会给你O(n)。


非常有趣的数据结构。 - Jeff Burdges

0

由于不允许额外空间,因此不能在没有比较的情况下完成。可以将比较排序时间复杂度的下界概念应用于此处,以证明该问题在其原始形式下无法在最坏情况下以O(n)的时间复杂度解决。


0
我们在这里也可以使用线性时间复杂度O(n)的方法。
public class DuplicateInOnePass {

    public static  void duplicate()

   {
        int [] ar={6,7,8,8,7,9,9,10};
        Arrays.sort(ar);
        for (int i =0 ; i <ar.length-1; i++)
        {


            if (ar[i]==ar[i+1])
                System.out.println("Uniqie Elements are" +ar[i]);

        }  

    }

    public static void main(String[] args) {
        duplicate();
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接