如何在O(n)时间中找到5个重复值?


15

假设您有一个大小为的数组,其中包含从到(含)在内的整数,并且正好重复了5个。我需要提出一种算法,该算法可以找到O(n)时间中的重复数。我一生都无法想任何事情。我认为排序最好是O(n \ log n)?然后遍历数组将是O(n),从而导致O(n ^ 2 \ log n)。但是,我不确定是否需要排序,因为我已经看到一些棘手的东西,包括链接列表,队列,堆栈等。1n61O n O n log n O n O n 2 log n n5O(n)O(nlogn)O(n)O(n2logn)


16
O(nlogn)+O(n)不是。是。如果您进行了n次排序,则结果为。O n log n O n 2 log n O(n2logn)O(nlogn)O(n2logn)
基金莫妮卡的诉讼


1
@leftaroundabout这些算法是,其中是数组的大小,是输入集的大小。由于这些算法适用于ñ ķ ķ = ñ - Ç ö Ñ 小号一个Ñ Ô Ñ 2O(kn)nkk=nconstantO(n2)
RomanGräf17年

4
@RomanGräf看来,实际情况是这样的:算法在,其中是域的大小。因此,对于像OP这样的问题,无论是在大小的域上使用这样的算法,还是在无边界大小的域上使用传统的算法,都归结为相同的问题。也有道理。ķ ñ ø Ñ · 登录Ñ O(logkn)knO(nlogn)
大约

5
对于,根据您的描述,唯一允许的数字是。但是,那么必须将重复六次,而不是五次。1 1n=611
亚历克斯·雷肯

Answers:


22

你可以创建一个额外的数组大小的。最初将数组的所有元素设置为。然后循环遍历输入数组并为每个将增大1 。之后,您只需检查数组:在循环,如果则重复。你在解决问题时间的内存成本,这是和因为你的整数是与和。n 0 A B [ A [ i ] ] i B A B [ A [ i ] ] > 1 A [ i ] O n O n 1 n - 5Bn0AB[A[i]]iBAB[A[i]]>1A[i]O(n)O(n)1n5


26

fade2black答案中的解决方案是标准解决方案,但它使用空间。您可以将其改进为O 1 空间,如下所示:O(n)O(1)

  1. 令数组为。对于d = 1 ... 5,计算σ d = Σ Ñ = 1名[ ] dA[1],,A[n]d=1,,5σd=i=1nA[i]d
  2. 计算(可以使用公知的公式来计算在后者总和Ô 1 )。注意τ d = d 1 + + d 5,其中1... 5是重复的编号。τd=σdi=1n5idO(1)τd=m1d++m5dm1,,m5
  3. 计算多项式。此多项式的系数是对称函数1... 5可以从计算τ 1...... τ 5Ö 1 P(t)=(tm1)(tm5)m1,,m5τ1,,τ5O(1)
  4. 通过尝试所有n - 5个可能性,找到多项式的所有根。P(t)n5

该算法假定采用RAM机器模型,其中对位字进行基本算术运算需要O 1 时间。O(logn)O(1)


制定此解决方案的另一种方法是遵循以下思路:

  1. 计算,并使用公式y 1 = x 1 - n - 5 i = 1 i推导y 1 = m 1 + + m 5x1=i=1nA[i]y1=m1++m5y1=x1i=1n5i
  2. 计算ø Ñ 使用公式 X 2 = [ 1 ] [ 2 ] + [ 1 ] + [ 2 ] A [ 3 ] + A [ 1x2=1i<jA[i]A[j]O(n)
    x2=(A[1])A[2]+(A[1]+A[2])A[3]+(A[1]+A[2]+A[3])A[4]++(A[1]++A[n1])A[n].
  3. 推断使用公式 Ŷ 2 = X 2 - Σ 1 < Ĵ ñ - 5Ĵ - ñ - 5 Σ= 1 ÿ 1y2=1i<j5mimj
    y2=x21i<jn5ij(i=1n5i)y1.
  4. 计算并沿相似的直线推导y 3y 4y 5x3,x4,x5y3,y4,y5
  5. 的值是(高达符号)的多项式的系数P 从前面的溶液。y1,,y5P(t)

该解决方案表明,如果将5替换为,则可以使用O d 2空间获得(我相信)O d 2 n 算法,该算法对位长为O的整数执行O d n 算术运算d log n ,在任何给定时间最多保留O d )个。(这需要仔细分析我们执行的乘法,其中大多数涉及一个仅长度为O的操作数log ndO(d2n)O(d2)O(dn)O(dlogn)O(d)。)可以想象,可以使用模块化算法将其改进为 O d n 时间和 O d 空间。O(logn)O(dn)O(d)


的任何解释τ dP 中号等?为什么ð { 1 2 3 4 5 }σdτdP(t)mid{1,2,3,4,5}
发泡胶飞

3
解决方案背后的洞察力是求和技巧,它在许多练习中都出现(例如,如何从长度为的数组中找到缺失的元素,该数组包含数字1 n中的一个?求和技巧可用于计算任意函数f的f m 1+ + f m 5,问题是选择哪个f才能推导出m 1mn11,,nf(m1)++f(m5)ff。我的答案使用了对称函数基本理论中的熟悉技巧。m1,,m5
Yuval Filmus

1
@hoffmale实际上,O(d2)
Yuval Filmus

1
@hoffmale每个人都用机器字。d
Yuval Filmus

1
@BurnsBA这种方法的问题是n - 4 n - 5 大得多(n5)#。大量操作较慢。(n4)(n5)2
Yuval Filmus

8

还有一种基于分区的线性时间和恒定空间算法,如果您尝试将其应用于数学方法无法很好解决的问题的变体,则该方法可能会更加灵活。与数学方法相比,这需要对基础数组进行变异,并且常数因子更差。更具体地说,我相信,就值的总数和重复项d的数量而言,代价是分别为On log d Od ,尽管严格证明它将比我目前花费更多的时间。 。ndO(nlogd)O(d)


算法

从对的列表开始,其中第一对是整个数组的范围如果为1索引,则为[(1,n)]

重复以下步骤,直到列表为空:

  1. 从列表中取出并删除任何一对(i,j)
  2. 找到指定子数组的最小和最大值maxminmax
  3. 如果,则子数组仅包含相等的元素。屈服除一个元素以外的元素,并跳过步骤4至6。min=max
  4. 如果,则子数组不包含重复项。跳过步骤5和6。maxmin=ji
  5. min + max附近对子数组进行分区,使得直到某个索引k的元素小于分隔符,而在该索引之上的元素不小于分隔符。min+max2ķ
  6. k + 1 j )添加到列表中。一世ķķ+1Ĵ

时间复杂度的课程分析。

步骤1至6花费时间,因为找到最小和最大值以及划分可以在线性时间内完成。ØĴ-一世

列表中的每对要么是第一对((1 n ,要么是某对的子代,其对应的子数组包含一个重复的元素。有至多d 登录2周 Ñ + 1 这样的父母,由于每个遍历半部的范围内,其中一个重复的就可以了,所以有至多2 d 登录2 Ñ + 1个总包括对在子阵列没有时重复。在任何时候,列表的大小不超过2 d一世Ĵ1ñd日志2ñ+12d日志2ñ+12d

考虑找到任何重复的工作。它由一个在指数递减范围内的成对序列组成,因此总功是几何序列的总和,即。这产生了一个明显的推论,即d个重复项的总功必须为On d ,它在n中是线性的。ØñdØñdñ

要找到更严格的界限,请考虑最大程度地分散副本的最坏情况。直观地讲,搜索过程分为两个阶段,一个阶段每次遍历整个数组,每个阶段逐渐变小,而另一个阶段小于因此只遍历数组的一部分。第一阶段只能是logd深度,因此成本为Onlogd,第二阶段具有成本On),因为要搜索的总面积再次呈指数下降。ñd日志dØñ日志dØñ


谢谢你的解释。现在我明白了。一个非常漂亮的算法!
DW

5

将此作为答案,因为它需要的空间比评论所需要的空间大。

当您建议一种方法时,会在OP中出错。排序列表,然后遍历时间,而不是O n 2 log n 时间。当您依次执行两项操作(分别取O f O g )时,结果时间复杂度为O f + g = O max f g(在大多数情况下)。Øñ日志ñØñ2日志ñØFØGØF+G=Ø最大值FG

为了增加时间复杂度,您需要使用for循环。如果您有一个长度为的循环,并且对于循环中的每个值,您都执行一个函数O g ,那么您将获得O f g 时间。FØGØFG

因此,在您的情况下,您以排序,然后以O n 进行横向运算,从而得出O n log n + n = O n log n 。如果对于排序算法的每次比较,您都必须进行O n 的计算,它将采用O n 2 log n ),但是这里不是这种情况。Øñ日志ñØñØñ日志ñ+ñ=Øñ日志ñØñØñ2日志ñ


如果您对我声称感到好奇,请务必注意并非总是如此。但是,如果˚F Ô ø ˚F (其适用于常用功能整个主机),它会保持。它最不常用的时间是当涉及到其他参数时,您会得到诸如O 2 c n + n log n )的表达式。ØF+G=Ø最大值FGFØGGØFØ2Cñ+ñ日志ñ


3

布尔数组技术有一个很明显的就地变体,它使用元素的顺序作为存储(arr[x] == x“找到”元素的位置)。不像分区变体可以被证明更通用,我不确定何时真正需要这样的东西,但这很简单。

for idx from n-4 to n
    while arr[arr[idx]] != arr[idx]
        swap(arr[arr[idx]], arr[idx])

这只是反复放置arr[idx]在该位置,arr[idx]直到您找到该位置为止,此时该位置必须是重复的。请注意,交换的总数受限制,因为每次交换都会使其退出条件正确。ñ


您将不得不提出某种论点,即内部while循环平均在恒定时间内运行。否则,这不是线性时间算法。
David Richerby '17

@DavidRicherby它不会平均运行恒定时间,但是外部循环只能运行5次,这样就可以了。请注意,交换的总数受限制,因为每次交换都会使其退出条件正确,因此,即使重复值的数量增加,总时间也仍然是线性的(aka。需要n步而不是n d)。ñññd
Veedrac

糟糕,我不知何故没有注意到外循环运行了恒定的次数!(经过编辑,以包括您有关掉期数量的注释,也可以使我
退缩

1

从和中减去你具有值一世=1ñ一世=ñ-1ñ2

于是,经过时间(假设算术是O(1),它是不是真的,但让我们假装)你有一笔σ 1 1到n之间的5整数:Θñσ1

X1+X2+X3+X4+X5=σ1

据说这不好,对吧?您可能无法弄清楚如何将其分解为5个不同的数字。

啊,但这就是有趣的地方!现在执行与以前相同的操作,但从n i = 1 i 2中减去值的平方。现在您有了:一世=1ñ一世2

X12+X22+X32+X42+X52=σ2

看到我要去哪里了吗?对3、4和5的幂进行相同的操作,您将在5个变量中拥有5个独立方程。我很确定您可以解决X

注意事项:算术不是真的 O(1)。另外,您需要一些空间来表示您的总和。但并不像你想象的-你可以做模块化最一切,只要你有,哦,位; 应该这样做。日志5ñ6


@YuvalFilmus是否提出相同的解决方案?
fade2black

@ fade2black:哦,是的,的确如此,对不起,我刚刚看到了他的解决方案的第一行。
einpoklum

0

解决问题的最简单方法是创建一个数组,在该数组中,我们将对原始数组中每个数字的出现次数进行计数,然后遍历从n - 5的所有数字,并检查该数字是否出现一次以上,因此这很复杂内存和时间中的解都是线性的,或者是O N 1ñ-5Øñ


1
这与@ fade2black的答案相同(尽管在眼睛上容易一些)
LangeHaare

0

将数组映射到1 << A[i],然后将所有内容异或。您的重复项将是关闭相应位的数字。


一共有五个重复项,因此xor技巧在某些情况下不会中断。
Evil

1
该程序的运行时间为。每个位向量的长度为n位,因此您每个位向量的操作花费O n 时间,并且对原始数组的每个元素执行一次位向量操作,总共需要O n 2时间。Øñ2ñØñØñ2
DW

@DW但是鉴于我们通常使用的机器固定为32位或64位,并且它们在运行时不会改变(即它们是恒定的),所以为什么不应该将它们这样对待并假设位操作是在而不是O n )中O(1)O(n)
code_dredd

1
@ray,我想您回答了您自己的问题。假设我们通常使用的机器固定为64位,则对位向量进行运算的运行时间为O n ,而不是O 1 。在n位向量的所有n位上执行某些操作都需要n / 64条指令,并且n / 64O n ,而不是O 1 nO(n)O(1)n/64nnn/64O(n)O(1)
DW

@DW我从以前得到的东西。有人评论说,位向量是指大小的数组中的单个元素,位向量是64位,这就是我要指的常数。显然,如果我们假设每个元素有k位并且数组中的元素数为n,则处理大小为n的数组将花费O k n 时间。但是k = 64,因此对数组元素w /恒定位数的操作应为O 1 而不是O k ,并且数组OnnO(kn)knk=64O(1)O(k)代替 O k n 。您是出于完整性/正确性而保留 k还是我遗漏了其他东西?O(n)O(kn)k
code_dredd

-2
DATA=[1,2,2,2,2,2]

from collections import defaultdict

collated=defaultdict(list):
for item in DATA:
    collated[item].append(item)
    if len(collated) == 5:
        return item.

# n time

4
欢迎来到该网站。我们是计算机科学站点,因此我们正在寻找算法和解释,而不是需要了解特定语言及其库的代码转储。特别是,您声称此代码以线性时间运行的主张是假设其collated[item].append(item)以恒定时间运行。是真的吗
David Richerby '17

3
此外,您正在寻找一个重复五次的值。相反,OP寻找五个值,每个值重复两次。
Yuval Filmus
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.