My attempt:
The array A
is assumed 1-indexed. We call an active value one that is nonzero and does not exceed n
.
Scan the array until you find an active value, let A[i] = k
(if you can't find one, stop);
While A[k]
is active,
- Move
A[k]
to k
while clearing A[k]
;
Continue from i
until you reach the end of the array.
After this pass, all array entries corresponding to some integer in the array are cleared.
- Find the first nonzero entry, and report its index.
E.g.
[5, 3, 2, 7], clear A[3]
[5, 3, 0, 7], clear A[2]
[5, 0, 0, 7], done
The answer is 1
.
E.g.
[5, 3, 2, 7, 1], clear A[5],
[5, 3, 2, 7, 0], clear A[1]
[0, 3, 2, 7, 0], clear A[3],
[0, 3, 0, 7, 0], clear A[2],
[0, 0, 0, 7, 0], done
The answer is 4
.
The behavior of the first pass is linear because every number is looked at once (and immediately cleared), and i
increases regularly.
The second pass is a linear search.
A= [5, 3, 2, 7, 1]
N= len(A)
print(A)
for i in range(N):
k= A[i]
while k > 0 and k <= N:
A[k-1], k = 0, A[k-1] # -1 for 0-based indexing
print(A)
[5, 3, 2, 7, 1]
[5, 3, 2, 7, 0]
[0, 3, 2, 7, 0]
[0, 3, 2, 7, 0]
[0, 3, 0, 7, 0]
[0, 0, 0, 7, 0]
[0, 0, 0, 7, 0]
Update:
Based on גלעד ברקן's idea, we can mark the array elements in a way that does not destroy the values. Then you report the index of the first unmarked.
print(A)
for a in A:
a= abs(a)
if a <= N:
A[a-1]= - A[a-1] # -1 for 0-based indexing
print(A)
[5, 3, 2, 7, 1]
[5, 3, 2, 7, -1]
[5, 3, -2, 7, -1]
[5, -3, -2, 7, -1]
[5, -3, -2, 7, -1]
[-5, -3, -2, 7, -1]