Wydaje mi się, że wpadłem na coś, co powinno działać ogólnie i wydajnie, jeśli masz gwarancję, że nie będziesz mieć duplikatów * (jednak powinno być rozszerzalne na dowolną liczbę dziur i dowolny zakres liczb całkowitych).
Pomysł tej metody jest podobny do szybkiego sortowania, polegającego na tym, że wokół niej znajduje się czop i przegroda, a następnie nawiercane po bokach z otworem. Aby zobaczyć, które strony mają otwór, znajdujemy najniższą i najwyższą liczbę i porównujemy je z osią obrotu i liczbą wartości po tej stronie. Załóżmy, że oś obrotu to 17, a minimalna liczba to 11. Jeśli nie ma otworów, powinno być 6 liczb (11, 12, 13, 14, 15, 16, 17). Jeśli jest ich 5, wiemy, że po tej stronie jest dziura i możemy po tej stronie wrócić, aby ją znaleźć. Mam problem z wyjaśnieniem tego bardziej precyzyjnie, więc weźmy przykład.
15 21 10 13 18 16 22 23 24 20 17 11 25 12 14
Sworzeń:
10 13 11 12 14 |15| 21 18 16 22 23 24 20 17 25
15 jest osią obrotu oznaczoną potokami ( ||
). Po lewej stronie osi obrotu znajduje się 5 cyfr, takich jak powinno być (15–10), i 9 po prawej stronie, gdzie powinno być 10 (25–15). Tak więc powracamy po prawej stronie; zauważymy, że poprzednia granica wynosiła 15 w przypadku, gdy otwór przylega do niej (16).
[15] 18 16 17 20 |21| 22 23 24 25
Teraz po lewej stronie są 4 liczby, ale powinno być 5 (21–16). Wracamy więc tam i ponownie zanotujemy poprzednią granicę (w nawiasach).
[15] 16 17 |18| 20 [21]
Lewa strona ma poprawne 2 liczby (18–16), ale prawa ma 1 zamiast 2 (20–18). W zależności od naszych warunków końcowych moglibyśmy porównać liczbę 1 z dwiema stronami (18, 20) i zobaczyć, czy brakuje 19 lub powtórzyć jeszcze raz:
[18] |20| [21]
Lewa strona ma rozmiar zero, z odstępem między czopem (20) a poprzednim obrzeżem (18), więc 19 to otwór.
*: Jeśli są duplikaty, prawdopodobnie możesz użyć zestawu skrótów, aby usunąć je w czasie O (N), zachowując ogólną metodę O (N), ale może to zająć więcej czasu niż użycie innej metody.