Я не уверен, как вы определяете «лучше», но, возможно, это подходит. По крайней мере, оно отличается от вашего решения и решений вопросов из связанного списка (каламбур).
Если мы сделаем путь
n+1 --> array[n+1] --> array[array[n+1]] --> ...
тогда этот путь содержит цикл тогда и только тогда, когда array^k[n+1] = array^l[n+1]
для некоторого k != l
, то есть, если и только если есть повторение. Теперь этот вопрос становится общей проблемой связанного списка, которую можно решить следующим образом.
Запустите две частицы на первом узле. Пусть первая частица движется с удельной скоростью, а вторая частица с удвоенной скоростью. Тогда, если есть цикл, вторая частица в конечном итоге будет возвращаться назад за первой, и в конце концов они будут такими же. Зачем? Что ж, если вы думаете о частицах как о круге (который они когда-то найдут в цикле), то в каждой единице времени вторая частица приближается на один шаг ближе к первой. Поэтому они должны в конечном итоге столкнуться. Тот, который они делают, вы нашли петлю. Чтобы найти повторяющееся значение, просто получите длину цикла, оставив одну частицу неподвижной, пока другая снова запускает цикл. Затем снова запустите обе частицы в начале, позвольте одному переместить длину цикла вперед, а затем направьте обе частицы вместе с постоянным расстоянием между ними, пока они не встретятся снова в начале цикла.
Поскольку некоторые комментаторы возмущены тем, что я не включил все детали того, как найти петлю в связанном списке, вот она сейчас. Нет обещаний, что это не ошибка (в конце концов, это псевдокод Matlab-esque), но это должно, по крайней мере, объяснить идею.
%% 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).