Zadanie polega na znalezieniu algorytmu O (1) o długości N wymaganej listy liczb. Nie ma więc znaczenia, czy potrzebujesz 100 najlepszych numerów, czy 10000 liczb, czas wstawienia powinien wynosić O (1).
Sztuczka polega na tym, że chociaż wspomniany jest wymóg O (1) dla wstawki listy, pytanie nie mówiło nic o kolejności czasu wyszukiwania w całej przestrzeni liczbowej, ale okazuje się, że można to zrobić O (1) także. Rozwiązanie jest następujące:
Umów się na tablicę skrótów z liczbami na klucze i parami połączonych wskaźników listy dla wartości. Każda para wskaźników jest początkiem i końcem połączonej sekwencji list. Zwykle będzie to tylko jeden element, a następnie następny. Każdy element na połączonej liście znajduje się obok elementu o kolejnym najwyższym numerze. Lista połączona zawiera posortowaną sekwencję wymaganych numerów. Przechowuj rekord o najniższej liczbie.
Weź nową liczbę x z losowego strumienia.
Czy jest wyższy niż ostatnio zarejestrowany najniższy numer? Tak => Krok 4, Nie => Krok 2
Traf w tablicę skrótów z właśnie pobraną liczbą. Czy jest wpis? Tak => Krok 5. Nie => Weź nową liczbę x-1 i powtórz ten krok (jest to proste wyszukiwanie liniowe w dół, po prostu zmiłuj się tutaj, można to poprawić, a ja wyjaśnię, jak)
Po uzyskaniu elementu listy z tabeli skrótów wstaw nowy numer zaraz po elemencie na liście połączonej (i zaktualizuj skrót)
Weź najniższą zarejestrowaną liczbę l (i usuń ją z mieszania / listy).
Traf w tablicę skrótów z właśnie pobraną liczbą. Czy jest wpis? Tak => Krok 8. Nie => Weź nową liczbę l + 1 i powtórz ten krok (jest to proste wyszukiwanie liniowe w górę)
Po trafieniu dodatnim liczba staje się nową najniższą liczbą. Przejdź do kroku 2
Aby pozwolić na zduplikowane wartości, skrót faktycznie musi utrzymywać początek i koniec połączonej sekwencji elementów, które są duplikatami. Dodanie lub usunięcie elementu pod danym klawiszem zwiększa lub zmniejsza wskazany zakres.
Tu wstawka to O (1). Wspomniane wyszukiwania to, jak sądzę, coś w rodzaju O (średnia różnica między liczbami). Średnia różnica rośnie wraz z rozmiarem przestrzeni liczbowej, ale maleje wraz z wymaganą długością listy liczb.
Zatem strategia wyszukiwania liniowego jest dość słaba, jeśli przestrzeń liczbowa jest duża (np. Dla typu int 4 bajtowego, od 0 do 2 ^ 32-1) i N = 100. Aby obejść ten problem z wydajnością, możesz przechowywać równoległe zestawy tablic mieszających, w których liczby są zaokrąglane do większych wielkości (np. 1s, 10s, 100s, 1000s), aby utworzyć odpowiednie klucze. W ten sposób możesz zwiększać i zmniejszać biegi, aby szybciej przeprowadzać wymagane wyszukiwania. Wydajność staje się wtedy O (logarytmiczny zakres), myślę, że jest stała, tj. O (1) również.
Aby to wyjaśnić, wyobraź sobie, że masz pod ręką liczbę 197. Trafiłeś tablicę haszującą 10s, z „190”, jest ona zaokrąglana do najbliższej dziesiątki. Byle co? Nie. Więc schodzisz za 10s, aż trafisz powiedz 120. Następnie możesz zacząć od 129 w tablicy 1s, a następnie spróbuj 128, 127, aż coś trafisz. Znalazłeś teraz miejsce na połączonej liście, aby wstawić numer 197. Podczas wpisywania musisz również zaktualizować tablicę hashtable 1 z wpisem 197, tablicę hasht z 10s o numerze 190, 100s ze 100 itd. Najwięcej kroków musisz tu zrobić 10 razy więcej niż dziennik zakresu liczb.
Mogłem pomylić niektóre szczegóły, ale ponieważ jest to wymiana programistów, a kontekstem były wywiady, mam nadzieję, że powyższe jest wystarczająco przekonującą odpowiedzią na tę sytuację.
EDYCJA Dodałem tutaj kilka dodatkowych szczegółów w celu wyjaśnienia równoległego schematu tablicy mieszającej i tego, jak to znaczy, że słabe wyszukiwania liniowe, o których wspomniałem, można zastąpić wyszukiwaniem O (1). Zdałem sobie również sprawę, że oczywiście nie ma potrzeby szukania następnej najniższej liczby, ponieważ możesz przejść od razu do niej, zaglądając do tablicy hasht z najmniejszą liczbą i przechodząc do następnego elementu.