如何解决在O1空间中的数组中找到重复元素的证明
鉴于数组的大小为n + 2,并且输入元素被限制在(1,n)范围内,因此我遇到了一种使用负数的方法(方法5,https://www.geeksforgeeks.org/find-the-two-repeating-elements-in-a-given-array/)使用O(1)空间查找重复项的问题。但是,我不完全相信为什么这样做有效,有人可以提供证明吗?
解决方法
要查看此算法是否有效,可能首先需要使用 extra 空间对其进行求解。
计数发生次数
创建一个名为count
的数组,其索引为1到n,并初始化为全零。这将跟踪您在输入数组中遇到某个值的频率。然后检查哪些计数大于1。因此算法(伪代码)非常简单:
count := array(n)
# initialise counts:
for i := 1 to n:
count[i] = 0
# start counting:
for value in A:
count[value] := count[value] + 1
# extract non-uniques
duplicates := array()
for i := 1 to n:
if count[i] > 1:
duplicates.append(i)
return duplicates
出现国旗事件
我们可以看到,当我们将计数从1增加到2时,我们已经可以检测到重复项。因此,我们真的不需要 store 计数2。我们可以保留计数为1并将该值添加到输出中。第一次遇到值时,对应的0将变为1,下次我们将看到已经存在1,并得出结论,我们有一个重复项(并保持原样保留1)。因此,通过这种方式,我们只需要存储两种值(0或1)。我们将为此辅助数组使用一个更合适的名称:它可以代替count
命名为found
。
found := array(n)
# initialise:
for i := 1 to n:
found[i] := 0
# loop and collect duplicates:
duplicates := array()
for value in A:
if found[value] == 0:
found[value] := 1
else: # already encountered this value before
duplicates.append(value)
return duplicates
将数据打包在一起
实际上只存储0或1就是存储一位。为了摆脱辅助空间,我们可以说我们肯定在输入数组的每个值中都有一个未使用的位可用:假定输入值都在1..n范围内,因此它们是正数,并且因此不使用符号位。我们可以在其中“隐藏”我们的位信息!
为此,我们必须确保该位的使用不会干扰输入值的存储。
因此,当我们从输入数组中读取一个值时,必须确保忽略该符号位(通过获取绝对值)。而且,当我们想读/写额外的位时,我们应该确保不要干扰原始的(正)输入值。位和值应共存而不互相影响。您可以将其视为包含2个数据的元组:1..n之间的一个位和一个数字。它们是无关的。
与上面的算法(使用found
)基本上没有什么不同。唯一的区别是两个(不相关的)数据打包在一起成为一个值。
我希望当您这样看时,算法会变得清晰。
备注
对此算法的一种批评是,它确实确实使用了多余的空间。假设您的输入由无符号字节组成,而 n 为255,那么实际上没有多余的空间了。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。