在列表中查找多个可能的重复整数中的任何一个

Dan*_*iel 12 algorithm search duplicates

给定的阵列n+1整数,每个范围1n,发现反复的整数.

在面试时我被问到这个问题.这是我的答案:鸽笼原则说必须重复一遍.我尝试使用二进制搜索方法,所以我在Matlab中做了这个,因为这就是我所知道的:

top = 0;
bot = 0;
for i=1:n+1
  if P[i] > n/2 
    top = top+1;
  else
    bot = bot+1;
end
Run Code Online (Sandbox Code Playgroud)

所以我认为其中一个,top或者bot,必须比n/2PhP 更大.取这个范围并重复.

我认为这是一个非常好的解决方案,但面试官有点暗示一个人可以做得更好.请发布您知道的更好的解决方案.

Pen*_*One 18

我不确定你是如何定义"更好"的,但也许这有资格.至少它与您的解决方案和链表问题的解决方案(双关语意图)不同.

如果我们走一条路

n+1 --> array[n+1] --> array[array[n+1]] --> ...
Run Code Online (Sandbox Code Playgroud)

那么这条路径包含一个循环,当且仅当array^k[n+1] = array^l[n+1]某些循环k != l,即当且仅当有重复时.现在问题变成了一个常见的链表问题,可以解决如下问题.

在第一个节点上启动两个粒子.让第一个粒子以单位速度移动,让第二个粒子以两倍的单位速度移动.然后,如果有一个循环,第二个粒子将最终循环回到第一个粒子后面,最终它们将是相同的.为什么?好吧,如果你把粒子想象成一个圆圈(它们将在找到环路时它们),每次单位时第二个粒子得到一个直接靠近第一个粒子的步骤.因此他们最终必须相互碰撞.他们一个人,你找到了一个循环.要找到重复的值,只需通过让一个粒子静止而另一个粒子再次运行循环来获得循环的长度.然后在开始时再次启动两个粒子,让一个移动前面的循环长度,然后将两个粒子一起运行,它们之间保持恒定距离,直到它们在循环开始时再次相遇.

由于一些评论员感到愤怒,我没有包括如何在链表中找到循环的所有细节,现在就是.没有承诺这不是错误的(毕竟它是Matlab式的伪代码),但它至少应该解释这个想法.

%% STEP 1: find a point in the cycle of the linked list using a slow and fast particle
slow = n+1;
fast = n+1;
for i=1 to n+1
    slow = array[slow];
    fast = array[array[fast]];
    if (slow == fast)
        break;
end

%% STEP 2: find the length of the cycle by holding one particle fixed
length = 1;
fast = array[fast]
while fast != slow
    fast = array[fast];
    length = length+1;
end

%% STEP 3: find the repeated element by maintaining constant distance between particles
slow = n+1;
fast = n+1;
for i=1 to length
    fast = array[fast];
end
while fast != slow
    fast = array[fast];
    slow = array[slow];
end

%% STEP 4: return the repeated entry
return slow;
Run Code Online (Sandbox Code Playgroud)

在这里我开始n+1因为array[i]介于1和n之间,所以这两个粒子都不会被送回n+1.这使得最多一次通过数组(虽然不按顺序)并跟踪两个粒子(慢和快)和一个整数(长度).因此空间为O(1),时间为O(n).

  • @丹尼尔:不,它不能。这是用于检测列表中循环的标准“指针追踪”技术。慢动作每一步+1,快动作+2,所以快“增益”每一步慢+1。它不能跳过它。 (2认同)
  • @Daniel:一个好问题,但想想当快粒子跟在慢粒子后面时会发生什么。如果斋戒落后一步,那么他们在下一步发生碰撞。如果快的落后两步,那么它们会分两步相撞。有道理。 (2认同)
  • @fiver:解决方案在任何时候都不正确,只是不完整.它说明了核心思想(循环检测),这对于那些认真思考完成算法的人来说已经足够了.但是,是的,完整的答案更好,现在就是这样.也许感谢您的评论.:-) (2认同)
  • 啊,关键部分是从元素n + 1开始,因为它不能成为任何"普通"无重复循环的一部分......非常聪明! (2认同)