给定的阵列n+1整数,每个范围1来n,发现反复的整数。
n+1
1
n
面试时有人问我。这是我的答案:鸽洞原理说必须重复一遍。我尝试使用二进制搜索方法,所以我在Matlab中做到了这一点,因为这就是我所知道的:
top = 0; bot = 0; for i=1:n+1 if P[i] > n/2 top = top+1; else bot = bot+1; end
因此,我认为其中之一(top或bot)必须n/2再次大于PhP。取该范围并重复。
top
bot
n/2
我认为这是一个很好的解决方案,但面试官暗示这可以做得更好。请发布您知道的任何更好的解决方案。
我不确定您如何定义“更好”,但是也许符合条件。至少与您的解决方案以及链表问题(双关语意味深远)的解决方案不同。
如果我们走一条路
n+1 --> array[n+1] --> array[array[n+1]] --> ...
然后,当且仅当array^k[n+1] = array^l[n+1]某某k != l(即,且仅当存在重复)时,此路径才包含一个循环。现在,该问题成为常见的链表问题,可以通过以下方式解决。
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;
我从这里开始是n+1因为array[i]介于1和n之间,所以两个粒子都不会被发送回n+1。这样最多可以通过数组一次(虽然不是按顺序排列),并且可以跟踪两个粒子(慢和快)和一个整数(长度)。因此,空间为O(1),时间为O(n)。
array[i]