Given an array of n+1
integers, each in the range 1
to n
, find an integer that is repeated.
I was asked this at a job intervi
This works in a similar way as @PengOne's answer but it is simpler I believe.
Explanation:
This approach treats the array as a graph where value at index i
points to index a[i]-1
(so value 1
points to index 0
). There is at least 1 repeating number, so the graph will be cyclic. There are n+1
elements and the max is n
, so the last node a[n+1]
will never be a part of a cycle but will enter a cycle. This is important as this last node is the start node
for traversal. Note that if a node which is part of a cycle is used as start node
with slow
(1x) and fast
(2x) pointers then they meet at that same node itself which is not useful. Let's call the converging node as meet node
. If the meet node
is k
hops away from the cycle node
, the start node
will also be k
hops away from the cycle node
. This logic is same as finding the cycle node in a cyclic linked list. The array is traversed a max of 3 times so O(n)
time and O(1)
space.
Algo:
a[n+1]
), find the meet node
using slow
(1x) and fast
(2x) pointers.meet node
and from start node
and they will converge at the cycle node
(The repeating numbers point to cycle node
). Code:
//pseudocode
//O(n) time, O(1) space
findrepeating(a):
x = findrepeating(a, findmeet(a), a[a.length() -1])
return x
findmeet(a):
slow = fast = a[a.length() -1]
while true:
slow = a[slow-1]
fast = a[a[fast-1]-1]
if slow == fast:
break
meet = slow // or fast
return meet
findrepeating(a, meet, start):
m = meet
s = start
while m != s:
m = a[m-1]
s = a[s-1]
return m // or s