To pytanie może być stare, ale nie mogłem wymyślić odpowiedzi.
Powiedzmy, że istnieją dwie listy o różnych długościach, łączące się w punkcie ; skąd wiemy, gdzie jest punkt łączenia?
Warunki:
- Nie znamy długości
- Każdą listę powinniśmy analizować tylko raz.
Odpowiedzi:
Jeśli
Rozwiązaniem byłby następujący algorytm.
Najpierw liczby. Załóżmy, że pierwsza lista ma długość,
a+c
a druga długośćb+c
, gdziec
jest długością ich wspólnego „ogona” (za punktem połączenia). Oznaczmy je następująco:Ponieważ nie znamy długości, obliczymy
x
iy
bez dodatkowych iteracji; zobaczysz jak.Następnie iterujemy każdą listę i odwracamy je podczas iteracji! Jeśli oba iteratory osiągną punkt scalenia w tym samym czasie, to dowiadujemy się tego przez zwykłe porównanie. W przeciwnym razie jeden wskaźnik osiągnie punkt scalenia przed drugim.
Po tym, gdy drugi iterator osiągnie punkt scalenia, nie przejdzie do wspólnego ogona. Zamiast tego wróci do poprzedniego początku listy, która wcześniej osiągnęła punkt scalenia! Tak więc, zanim osiągnie koniec zmienionej listy (tj. Poprzedni początek drugiej listy), dokona
a+b+1
sumowania iteracji. Nazwijmy toz+1
.Wskaźnik, który jako pierwszy osiągnął punkt scalenia, będzie kontynuował iterację, aż osiągnie koniec listy. Liczba wykonanych iteracji powinna zostać obliczona i jest równa
x
.Następnie ten wskaźnik wykonuje iterację wstecz i ponownie odwraca listy. Ale teraz nie wróci do początku listy, z której pierwotnie się rozpoczął! Zamiast tego przejdzie na początek drugiej listy! Liczba wykonanych iteracji powinna być obliczona i równa
y
.Znamy więc następujące liczby:
Z którego to ustalamy
Co rozwiązuje problem.
źródło
Oto zdecydowanie największe ze wszystkich, jakie widziałem - O (N), bez liczników. Zdobyłem go podczas rozmowy kwalifikacyjnej z kandydatem na SN w VisionMap .
Utwórz wskaźnik pośredni w ten sposób: przesuwa się do przodu za każdym razem do końca, a następnie przeskakuje na początek przeciwnej listy i tak dalej. Utwórz dwa z nich, wskazując na dwie głowy. Za każdym razem przesuń każdy ze wskaźników o 1, aż się spotkają. Stanie się to po jednym lub dwóch przejściach.
Nadal używam tego pytania w wywiadach - ale żeby zobaczyć, ile czasu zajmuje komuś zrozumienie, dlaczego to rozwiązanie działa.
źródło
a-b-c-x-y-z
ip-q-x-y-z
. ścieżka pierwszego wskaźnikaa,b,c,x,y,z,p,q,x
, ścieżka drugiego wskaźnikap,q,x,y,z,a,b,c,x
Odpowiedź Pawła wymaga modyfikacji list, a także dwukrotnego powtórzenia każdej z nich.
Oto rozwiązanie, które wymaga tylko dwukrotnego powtórzenia każdej listy (za pierwszym razem, aby obliczyć ich długość; jeśli podano długość, wystarczy powtórzyć tylko raz).
Chodzi o to, aby zignorować początkowe wpisy dłuższej listy (nie może tam być punktu scalającego), tak aby dwa wskaźniki znajdowały się w równej odległości od końca listy. Następnie przesuń je do przodu, aż się połączą.
Jest to asymptotycznie to samo (czas liniowy), co moja inna odpowiedź, ale prawdopodobnie ma mniejsze stałe, więc prawdopodobnie jest szybsze. Ale myślę, że moja druga odpowiedź jest fajniejsza.
źródło
Cóż, jeśli wiesz, że się połączą:
Powiedzmy, że zaczynasz od:
1) Przejdź przez pierwszą listę, ustawiając każdy następny wskaźnik na NULL.
Teraz masz:
2) Teraz przejrzyj drugą listę i poczekaj, aż zobaczysz NULL, czyli twój punkt łączenia.
Jeśli nie możesz być pewien, że się scalą, możesz użyć wartości wartowniczej dla wartości wskaźnika, ale nie jest to tak eleganckie.
źródło
Gdybyśmy mogli iterować listy dokładnie dwa razy, to mogę podać metodę określania punktu scalania:
źródło
Oto rozwiązanie, szybkie obliczeniowo (raz iteruje każdą listę), ale zużywa dużo pamięci:
źródło
Możesz użyć zestawu węzłów. Przejdź przez jedną listę i dodaj każdy węzeł do zestawu. Następnie iteruj przez drugą listę i dla każdej iteracji sprawdź, czy węzeł istnieje w zestawie. Jeśli tak, to znalazłeś swój punkt scalania :)
źródło
To prawdopodobnie narusza warunek „przeanalizuj każdą listę tylko raz”, ale zaimplementuj algorytm żółwia i zająca (używany do znajdowania punktu scalenia i długości cyklu listy cyklicznej), więc zaczynasz od listy A, a gdy osiągniesz NULL w koniec udajesz, że jest to wskaźnik do początku listy B, tworząc w ten sposób wygląd listy cyklicznej. Algorytm powie Ci wtedy dokładnie, jak daleko w dół listy A znajduje się scalanie (zmienna „mu” zgodnie z opisem w Wikipedii).
Ponadto wartość „lambda” mówi ci o długości listy B, a jeśli chcesz, możesz obliczyć długość listy A podczas wykonywania algorytmu (gdy przekierowujesz łącze NULL).
źródło
Może zbytnio to upraszczam, ale po prostu powtarzam najmniejszą listę i używam ostatnich węzłów
Link
jako punktu scalania?Tak więc, gdzie
Data->Link->Link == NULL
jest punktem końcowym, podającData->Link
jako punkt łączenia (na końcu listy).EDYTOWAĆ:
OK, z opublikowanego zdjęcia analizujesz dwie listy, najpierw najmniejszą. Przy najmniejszej liście możesz zachować odniesienia do następnego węzła. Teraz, kiedy analizujesz drugą listę, wykonujesz porównanie referencji, aby znaleźć referencję [i] w LinkedList [i] -> Link. To da punkt scalenia. Czas wyjaśnić zdjęciami (nałożyć wartości na obraz PO).
Masz połączoną listę (referencje pokazane poniżej):
A->B->C->D->E
Masz drugą połączoną listę:
1->2->
Po połączeniu listy odwołania wyglądałyby następująco:
1->2->D->E->
Dlatego mapujesz pierwszą „mniejszą” listę (ponieważ lista połączona, czyli to, co liczymy, ma długość 4, a lista główna 5)
Przejrzyj pierwszą listę, zachowaj referencje referencji.
Lista będzie zawierać następujące odniesienia
Pointers { 1, 2, D, E }
.Teraz przejdziemy przez drugą listę:
Jasne, utrzymujesz nową listę wskaźników, ale to nie jest poza specyfikacją. Jednak pierwsza lista jest analizowana dokładnie raz, a druga lista zostanie w pełni przeanalizowana tylko wtedy, gdy nie ma punktu scalania. W przeciwnym razie zakończy się wcześniej (w punkcie scalenia).
źródło
Przetestowałem przypadek scalania na moim FC9 x86_64 i wydrukowałem każdy adres węzła, jak pokazano poniżej:
Uwaga, ponieważ dopasowałem strukturę węzła, więc gdy malloc () jest węzłem, adres jest wyrównany z 16 bajtami, patrz co najmniej 4 bity. Najmniejsze bity to 0s, tj. 0x0 lub 000b. Więc jeśli masz ten sam specjalny przypadek (wyrównany adres węzła), możesz użyć tych co najmniej 4 bitów. Na przykład, gdy podróżujesz obie listy od początku do końca, ustaw 1 lub 2 z 4 bitów adresu węzła odwiedzającego, to znaczy ustaw flagę;
Uwaga, powyższe flagi nie wpłyną na rzeczywisty adres węzła, ale tylko na wartość wskaźnika ZAPISANEGO węzła.
Po znalezieniu ktoś ustawił bit (y) flagi, to pierwszy znaleziony węzeł powinien być punktem scalenia. Po zakończeniu można przywrócić adres węzła, usuwając ustawione bity flagi. podczas gdy ważną rzeczą jest to, że powinieneś być ostrożny podczas iteracji (np. node = node-> next) w celu wyczyszczenia. pamiętaj, że ustawiłeś bity flag, więc zrób w ten sposób
Ponieważ ta propozycja przywróci zmienione adresy węzłów, można to uznać za „brak modyfikacji”.
źródło
Może być proste rozwiązanie, ale będzie wymagało dodatkowej przestrzeni. Chodzi o to, aby przejść przez listę i zapisać każdy adres na mapie skrótów, teraz przejść przez drugą listę i sprawdzić, czy adres znajduje się na mapie skrótów, czy nie. Każda lista jest przeglądana tylko raz. Żadna lista nie jest modyfikowana. Długość jest nadal nieznana. Wykorzystana przestrzeń pomocnicza: O (n) gdzie „n” jest długością pierwszej listy, przez którą przeszedł.
źródło
to rozwiązanie iteruje każdą listę tylko raz ... nie jest też wymagana modyfikacja listy ... chociaż możesz narzekać na spację ..
1) Zasadniczo wykonujesz iterację w liście1 i przechowujesz adres każdego węzła w tablicy (która przechowuje wartość int bez znaku)
2) Następnie iterujesz listę2 i dla adresu każdego węzła ---> przeszukujesz tablicę, w której znajdujesz dopasowanie lub nie ... jeśli to zrobisz, to jest to węzeł scalający
Mam nadzieję, że to prawidłowe rozwiązanie ...
źródło
Nie ma potrzeby modyfikowania żadnej listy. Istnieje rozwiązanie, w którym każdą listę musimy przejść tylko raz.
źródło
źródło
Oto naiwne rozwiązanie, nie ma potrzeby przechodzenia przez całe listy.
jeśli twój węzeł strukturalny ma trzy pola, takie jak
powiedz, że masz dwie głowy (head1 i head2) wskazujące na nagłówki dwóch list.
Przejrzyj obie listy w tym samym tempie i umieść flagę = 1 (flaga odwiedzonych) dla tego węzła,
źródło
Co powiesz na to:
Jeśli możesz przejść przez każdą listę tylko raz, możesz utworzyć nowy węzeł, przejść przez pierwszą listę, aby każdy węzeł wskazywał na ten nowy węzeł, i przejść przez drugą listę, aby sprawdzić, czy któryś węzeł wskazuje na nowy węzeł ( to jest twój punkt łączenia). Jeśli drugie przejście nie prowadzi do nowego węzła, oryginalne listy nie mają punktu scalenia.
Jeśli możesz przeglądać listy więcej niż raz, możesz przejść przez każdą listę, aby znaleźć nasze długości, a jeśli są różne, pomiń „dodatkowe” węzły na początku dłuższej listy. Następnie po prostu przejrzyj obie listy krok po kroku i znajdź pierwszy węzeł scalający.
źródło
Kroki w Javie:
źródło
Możemy go skutecznie rozwiązać, wprowadzając pole „isVisited”. Przejdź przez pierwszą listę i ustaw wartość „isVisited” na „true” dla wszystkich węzłów do końca. Teraz zacznij od drugiego i znajdź pierwszy węzeł, w którym flaga jest prawdą i Boom, to twój punkt łączenia.
źródło
Krok 1: znajdź długość obu list Krok 2: znajdź różnicę i przesuń największą listę z różnicą Krok 3: Teraz obie listy będą na podobnej pozycji. Krok 4: Powtarzaj listę, aby znaleźć punkt scalenia
źródło
źródło
Użyj mapy lub słownika, aby zapisać adres i wartość węzła. jeśli adres już został odczytany w Mapie / Słowniku, wówczas wartością klucza jest odpowiedź. Ja to zrobiłem:
źródło
AO (n) rozwiązanie złożoności. Ale na podstawie założenia.
założenie jest takie: oba węzły mają tylko dodatnie liczby całkowite.
logika: zmień wszystkie liczby całkowite z listy1 na ujemne. Następnie przejdź przez list2, aż otrzymasz ujemną liczbę całkowitą. Po znalezieniu => weź to, zmień znak z powrotem na dodatni i wróć.
źródło
Możemy użyć dwóch wskaźników i poruszać się w taki sposób, że jeśli jeden ze wskaźników jest zerowy, wskażemy go na początek drugiej listy i to samo dla drugiej, w ten sposób jeśli długości list są różne, spotkają się w drugim przebiegu . Jeśli długość listy1 jest n, a lista2 jest równa m, ich różnica wynosi d = abs (nm). Pokonają tę odległość i spotkają się w punkcie scalenia.
Kod:
źródło
Możesz dodać węzły
list1
do hashset i pętlę przez drugi, a jeśli którykolwiek węzełlist2
jest już obecny w zestawie. Jeśli tak, to jest to węzeł scalającyźródło
Rozwiązanie wykorzystujące javascript
źródło
Jeśli edytowanie połączonej listy jest dozwolone,
źródło