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 mpolega 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] != isugerowaliś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] != iczęś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 ifwarunku. 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 isatysfakcjonują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 mod bycia wyjście jako duplikaty powodując 2. połowę swoich ifwarunkach zawodzą, ale to będzie działać, gdy iprzybywa do lokalizacji domowej m? Tak, będzie, ponieważ teraz, chociaż iteraz okazuje się, że pierwsza połowa ifwarunku A[i] != ijest 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 mczy 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 mi 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ę.