面试任务:检查数组是否包含O(n)时间和O(1)附加内存中的对

时间:2015-12-24 15:34:56

标签: arrays algorithm

以下是我在面试中被问到的任务的一个例子,我认为这个任务拼写错误或定义不正确但也许我错了,所以这里有:

需要提供一个函数实现,它检查参数数组是否只包含重复项,例如提供了两个数组:

var x = [11,12,11,12]; // True, array consists of duplicates
var y = [66, 3278, 12, 12]; // False, 66 and 3278 contain no pair

问题在于约束,算法应该在O(n)时间内执行此检查,使​​用O(1)内存空间

你怎么想,是否可能,因为我没有看到可能发生的方式......

5 个答案:

答案 0 :(得分:6)

不可能的结果比算法要困难得多,所以有一个看似无法解决的问题是令人沮丧的。

当然,没有一次通过算法,通过输入中点的通信复杂性参数。使用(例如)只有k个存储字,从第一个k + 1个项目中记住精确的多个集合是不可能的,因此我们可以使用另一个导致输出不正确的k + 1来跟踪这些项目。

另一方面,有一种概率算法在大多数情况下成功。计算应用于每个输入元素的伪随机函数的XOR,并且当且仅当XOR为0时才返回元素配对。正如Peter在注释中观察到的那样,不足以让伪随机函数成为身份,由于输入{0,1,2,3}。 PRF的要点是使线性代数的性质超过Z / 2,使得得到假零的概率等于随机字为零的概率,对于长字来说,这个概率非常小

答案 1 :(得分:2)

  • 从1开始。
  • 对于每个数字x,从数组中乘以第x个素数。
  • 如果结果是平方数,则该数组仅包含重复项。 (或者可能是几个四倍,或其他多重双胞胎)

答案 2 :(得分:1)

David提供了一个实用的解决方案,它始终在O(n)时间运行,几乎总能产生正确的答案。

你应该接受大卫的回答,但要记录:

始终产生正确答案但在预期线性时间内运行的解决方案是将数组逐步转换为开放式地址哈希表,在发现它们时删除重复项。

有一些技巧需要逐步完成,我不会扩展,因为这不是最实际的答案。

答案 3 :(得分:1)

首先,问题有点不明确。数组中的元素类型是什么?输入是否来自任何分布(可能所有元素都来自“小”集或“小”间隔,因此您可以应用一些类似于countort的方法或其他一些简单的方法)?我会问所有这些。当您遇到涉及复杂性理论概念的问题时,它们是非常重要的方面。如果你不了解这些细节,那么O(1)首先意味着什么并不是很清楚。

但由于他们都没有答案,我认为你需要提供一个通用的解决方案。然而,极其合理的是,数组中的每个元素都可以用有限的常数位(比如L位)来表示。假设这一点,由于L是常数,2 L 也是一个常数,因此,分配2 L 位的解决方案满足O(1)记忆约束。您现在可以选择在迭代输入数组时设置和重置上述位图中的位条目的解决方案。

你的面试官正在寻找类似的东西是不可信的,但从复杂性理论的角度来看,这是一个非常有效的答案,我会在面试中提供它作为第一个解决方案。但是,我同意,根据2 L n之间的关系及其大小,这种方法可能导致实现效率极低。

答案 4 :(得分:1)

由于数字在实践中具有固定长度,因此任何基于基数的方法在技术上都会给出O(N)运行时间,O(1)存储器复杂度。如果需要,可以将浮点数视为整数(如果允许字符串,则不清楚)。

现在,基数排序通常需要一个辅助数组来存储数字排序的数字,但排序也可以通过"递归交换"来完成,即我们从单元格i中获取一个数字,我们有把它放到单元格j中,所以我们用它替换单元格j中的数字,然后对j进行相同的操作,重复直到我们返回到单元格i。它需要一个额外的位来标记已经处理过的单元格。在实践中你应该能够使用一些较高的位,但如果面试官是一个混蛋并且不允许它,我只使用一个完整的2 ^ 32基数的单一传球,这在技术上仍然是O(1)。这种递归交换不是一个稳定的排序,所以你不能使用LSD排序,但MSD排序与递归应该仍然有效。当然,对于最后一位数字,您不必进行任何实际排序,只需检查所有桶中的计数是否均匀。

显然,如果可以修改原始数组,这种方法就会引发问题。如果没有,我怀疑任何非概率解决方案都是可能的。