Znakomita odpowiedź caf wypisuje każdą liczbę, która pojawia się k razy w tablicy k-1 razy. To przydatne zachowanie, ale pytanie prawdopodobnie wymaga, aby każdy duplikat był drukowany tylko raz, a on nawiązuje do możliwości zrobienia tego bez przekraczania granic czasu liniowego / stałej przestrzeni. Można to zrobić, zastępując jego drugą pętlę następującym pseudokodem:
for (i = 0; i < N; ++i) {
if (A[i] != i && A[A[i]] == A[i]) {
print A[i];
A[A[i]] = i;
}
}
Wykorzystuje to właściwość, która m
polega na tym, że po uruchomieniu pierwszej pętli, jeśli jakakolwiek wartość pojawi się więcej niż raz, to jeden z tych wyglądów będzie miał właściwą pozycję, a mianowicie A[m]
. Jeśli będziemy ostrożni, możemy użyć tej „domowej” lokalizacji do przechowywania informacji o tym, czy jakiekolwiek duplikaty zostały jeszcze wydrukowane, czy nie.
W wersji caf, gdy przeszliśmy przez tablicę, A[i] != i
sugerowaliśmy, że A[i]
jest to duplikat. W mojej wersji opieram się na nieco innym niezmienniku: A[i] != i && A[A[i]] == A[i]
oznacza A[i]
to, że jest to duplikat , którego wcześniej nie widzieliśmy . (Jeśli pominiesz część „której nie widzieliśmy wcześniej”, resztę można uznać za wynikającą z prawdy niezmiennika kawiarni i gwarancji, że wszystkie duplikaty mają jakąś kopię w lokalizacji domowej). początek (po zakończeniu pierwszej pętli kawiarni) i pokazuję poniżej, że jest utrzymywany po każdym kroku.
Gdy przechodzimy przez tablicę, sukces A[i] != i
części testu sugeruje, że A[i]
może to być duplikat, którego wcześniej nie widziano. Jeśli wcześniej tego nie widzieliśmy, spodziewamy się A[i]
, że lokalizacja domu wskazuje na siebie - to jest sprawdzane pod kątem drugiej połowy if
warunku. W takim przypadku drukujemy go i zmieniamy lokalizację początkową, aby wskazywała z powrotem na ten pierwszy znaleziony duplikat, tworząc dwuetapowy „cykl”.
Aby zobaczyć, że ta operacja nie zmienia naszego niezmiennika, załóżmy, że m = A[i]
określona pozycja jest i
satysfakcjonująca A[i] != i && A[A[i]] == A[i]
. To oczywiste, że zmiana robimy ( A[A[i]] = i
) będzie działać, aby zapobiec inne wystąpienia non-domu m
od bycia wyjście jako duplikaty powodując 2. połowę swoich if
warunkach zawodzą, ale to będzie działać, gdy i
przybywa do lokalizacji domowej m
? Tak, będzie, ponieważ teraz, chociaż i
teraz okazuje się, że pierwsza połowa if
warunku A[i] != i
jest prawdziwa, druga połowa sprawdza, czy lokalizacja, na którą wskazuje, jest lokalizacją domową i stwierdza, że tak nie jest. W tej sytuacji już nie wiem czy m
czy A[m]
był duplikatem wartość, ale wiemy, że tak czy inaczej,zostało to już zgłoszone , ponieważ gwarantuje się, że te 2 cykle nie pojawią się w wyniku pierwszej pętli kawiarni. (Zauważ, że jeśli m != A[m]
wtedy dokładnie jeden z m
i A[m]
występuje więcej niż raz, a drugi nie występuje w ogóle).
a[a[i]]
, a ograniczenie spacji O (1) wskazuje naswap()
kluczową operację.