在 O(n) 和恒定空间中查找重复

Posted

技术标签:

【中文标题】在 O(n) 和恒定空间中查找重复【英文标题】:Find repeating in O(n) and constant space [duplicate] 【发布时间】:2012-02-22 18:17:48 【问题描述】:

可能重复:Easy interview question got harder: given numbers 1..100, find the missing number(s)Find the missing and duplicate elements in an array in linear time and constant space

我在一个论坛上看到了一个有趣的问题。

您有 100 个从 1 到 100 的元素,但错误地其中一个数字通过重复自身而与另一个数字重叠。 例如。 1,99,3,...,99,100 数组未排序,如何找到重复的数字?

我知道 Hash 可以做到 O(n) 时间和 O(n) 空间,我需要 O(1) 空间。

【问题讨论】:

为什么你接受了错误的答案? (不是 O(1) 空间) 【参考方案1】:

我们可以在 O(n) 和常数空间中做到这一点:

    对于每个元素,计算index = Math.abs(a[i]) - 1 检查index的值 如果是正数,则乘以 -1,即变为负数。 如果是否定的,返回 (index+1) 作为答案,因为这意味着我们以前见过这个索引。

""

static int findDup(int[] a)
    for(int i=0;i<a.length;i++)
        int index = Math.abs(a[i]) - 1;
        if(a[index] < 0)
            return index+1;
        else
            a[index] = -1 * a[index];
    
    return -1;

【讨论】:

您正在为输入中的每个元素(可能)存储一条信息。这不是恒定的空间。 @Nick 为什么你认为它不是恒定的空间?我使用相同的数组来存储 -ve 符号 @Manan 您仍在使用线性空间来构建您的解决方案。如果您的输入集是不可变的,或者不能随机访问,或者不支持有符号整数,那么您需要自己创建这个数组。 @Manan 问题中没有明确给出这些约束(具有恒定时间随机访问的可修改签名输入),因此假设它们有点牵强。但无论如何,这仍然不符合常数空间算法的条件。这不是 malloc() 需要多少字节的问题;这是你需要记录多少条信息的问题。 @Manan a[index] = -1 * a[index]; 行覆盖输入。这就是为什么人们说这个解决方案不是恒定空间。【参考方案2】:

计算两个和:总和和平方和。

在你的例子中:

sum = 1+99+3...+100

sq_sum = 1^2+99^2+3^2+...+100^2

假设 y 替换了序列中的 x。

sum = n(n+1)/2 -y+x.
sq_sum = n(n+1)(2n+1)/6 -x^2 +y^2

现在,求解 x 和 y。

恒定空间和 O(n) 时间。

如何求解 x 和 y

​​>

从方程:

x = sum - n(n+1)/2 +y

将其代入第二个等式:

sq_sum = n(n+1)(2n+1)/6 -(sum - n(n+1)/2 +y)^2 +y^2

请注意,y^2 取消,您将得到一个只有一个未知数的线性方程:y。解决它!

【讨论】:

这个答案有 2 票反对票,没有 cmets。请在此处解释不正确之处,以便 OP 可以反驳或修改,并让其他人了解(潜在)问题。 你如何为 x&y 解决这个问题? 确实需要平方和,如果数组长度为 101 并且有 100 个唯一值,那么您将这 100 个唯一值相加得到 5050,假设总和返回为 5149,您立即知道99 被重复,当有多个重复但问题只提到一个值重复一次时,这不起作用。 @Seph 数组长度为100,一个数字重复,一个数字省略。因此有两个未知数,需要两个方程。 为什么有人会对正确答案投反对票?【参考方案3】:

新方法。让m 是缺失的数字,r 是重复的数字。通过数组一次,让X 成为XOR 数组条目连同索引1n 的结果。然后X = m XOR r。特别是,它不是0。让bX 的任何非零位(您只需要选择一个,并且存在一个,因为X 不是0)。通过数组,让Y 成为XOR 数组条目和索引1n 的结果,其中位b0 并让Z 成为结果的XORing 数组的条目和索引1n 其中位b1。然后YZ 持有mr,所以剩下的就是做最后一个pass,看看哪个在数组中。

总空间:4 个(如果您将 X 重复用于 b,则为 3 个)

总时间:7 次通过(如果您同时对数组执行索引并同时计算 YZ,则为 3 次。

因此O(1) 空间和O(n) 时间。

【讨论】:

你确定吗?第一步慢是n+1。所以 array[slow] 返回错误或垃圾,不是吗? 我仍然认为它行不通。考虑有多个周期的情况。或者考虑一个数组[n]=n的情况。 所以对于 X 的每个非零位,您都需要一个额外的通道,对吧?在那种情况下,您的解决方案 O(nlogn) 及时。我不太确定这个事实,但请告诉我。 @ElKamina 不,你只为你最喜欢的非零位做一次。您不必对每个非零位都执行此操作。它适用于任何非零位。 X 的大小是否取决于 n?如果是,那么它不是 O(1) 空间。【参考方案4】:

计算所有整数的总和 计算 int p = sum % 100 100 - p 就是答案

【讨论】:

这只会让您区分丢失的号码和重复的号码,但不足以识别其中任何一个。你有两个未知数,你需要方程。请参阅上面 ElKamina 的回答。 这是不正确的。采取两种情况:5 被 10 替换,6 被 11 替换。在这两种情况下,总和将是相同的。 示例 1,99,3,4...100。现在 sum % 100 将是 98。100-98 是 2 :) @topcoder 我得到 1+99+3+4+...+100 % 100 = 47。 @NickBarnes 1 到 100 模 100 的总和不是 0。为什么大家都认为它是? 1+2+...+100 = 5050!!

以上是关于在 O(n) 和恒定空间中查找重复的主要内容,如果未能解决你的问题,请参考以下文章

在 O(1) 空间中的数组中查找重复元素(数字不在任何范围内)

查找数组中重复的唯一元素+时间复杂度O(n)+空间复杂度O

287 Find the Duplicate Number 寻找重复数

我们如何在 O(n) 时间和 O(1) 空间复杂度内找到数组中的重复数字

找到具有 O(1) 空间和 O(n) 时间的重复数字

剑指offer_查找数组中的任一重复元素