Перевірте, чи поєднуються два пов'язані списки. Якщо так, то де?


102

Це питання може бути старим, але я не міг придумати відповіді.

Скажімо, є два списки різної довжини, що зливаються в точці ; як ми можемо знати, де знаходиться точка злиття?

Умови:

  1. Ми не знаємо довжини
  2. Ми повинні проаналізувати кожен список лише один раз.

Приклад двох об'єднаних пов'язаних списків.


засоби злиття з цього моменту буде лише один список.
rplusg

чи дозволяється зміна списку?
Артелій

1
Я впевнений, що це не працює без зміни списку. (Або просто скопіюйте його десь в іншому місці, щоб уникнути обмеження проаналізувати його лише один раз.)
Георг Шоллі

2
Можливо, справа була в цьому. Чортові інтерв'юери! Хехе
Кайл Розендо

1
У мене цікава пропозиція ... припустимо, що загальний хвіст списку нескінченно довгий. Як можна знайти перетин вузла за допомогою постійної пам'яті?
Акусете

Відповіді:


36

Якщо

  • під "модифікацією не дозволено" малося на увазі "ви можете змінити, але врешті-решт вони повинні бути відновлені", і
  • ми могли повторити списки рівно двічі

наступним алгоритмом було б рішення.

По-перше, числа. Припустимо, перший список має довжину, a+cа другий - довжину b+c, де cдовжина їх загального «хвоста» (після точки злиття). Позначимо їх так:

x = a+c
y = b+c

Оскільки ми не знаємо довжини, ми обчислимо xі yбез додаткових ітерацій; ви побачите як.

Потім ми повторюємо кожен список і повертаємо їх під час повторення! Якщо обидва ітератори досягають точки злиття одночасно, то ми з'ясовуємо це шляхом простого порівняння. В іншому випадку один вказівник досягне точки злиття перед іншим.

Після цього, коли інший ітератор досягне точки злиття, він не перейде до загального хвоста. Натомість повернемося до колишнього початку списку, який раніше досяг точки злиття! Отже, перш ніж він досягне кінця зміненого списку (тобто колишнього початку другого списку), він зробить a+b+1ітерації підсумковими. Давайте назвемо це z+1.

Вказівник, який спочатку досяг точки злиття, буде тримати ітерацію, поки не досягне кінця списку. Кількість ітерацій, які вона зробила, повинна бути обчислена і дорівнює x.

Потім цей покажчик повторює назад і повертає списки знову. Але тепер це не повернеться до початку списку, з якого він спочатку почався! Натомість він перейде на початок іншого списку! Кількість повторень, які вона зробила, повинна бути обчислена і дорівнює y.

Тож ми знаємо наступні цифри:

x = a+c
y = b+c
z = a+b

З чого ми визначаємо це

a = (+x-y+z)/2
b = (-x+y+z)/2
c = (+x+y-z)/2

Що вирішує проблему.


2
Коментар до запитання зміна списку заборонена!
Skizz

1
Мені подобається ця відповідь (дуже креативна). Єдина проблема, яка у мене є, це те, що він передбачає, що ви знаєте довжину обох списків.
tster

ви не можете змінювати список, і ми не знаємо довжини - це обмеження ... як завгодно, дякую за творчу відповідь.
rplusg

2
@tster, @calvin, відповідь не передбачає, нам потрібна довжина. Її можна обчислити в онлайні. Додавання пояснень до моїх відповідей.
П Швед

2
@Forethinker хешування відвіданих вузлів та / або маркування їх як побачених вимагає O (довжина списку) пам'яті, тоді як для багатьох рішень (включаючи моє, наскільки це недосконале і складне) потрібна O (1) пам'ять.
П Швед

156

Далі - це найбільше з усіх, що я бачив - O (N), лічильників немає. Я отримав це під час інтерв'ю кандидату SN у VisionMap .

Зробіть такий інтегральний вказівник таким чином: він щоразу рухається вперед до кінця, а потім переходить на початок протилежного списку тощо. Створіть дві з них, вказуючи на дві голови. Заздалегідь просувайте кожен із вказівників по 1 раз, поки вони не зустрінуться. Це станеться через один або два проходи.

Я все ще використовую це питання в інтерв'ю - але щоб побачити, скільки часу потрібно, щоб хтось зрозумів, чому це рішення працює.


6
це просто геніально!
Конг Хуй

2
Це хороша відповідь, але вам доведеться двічі пройти список, що порушує умову №2.
tster

2
Я вважаю це рішення досить елегантним, якщо точка злиття гарантовано присутня. Він не буде працювати для виявлення точок злиття, так як якщо такої немає, вона замикається нескінченно.
чергується напрямок

4
Це супер геніально! Пояснення: у нас є 2 списки: a-b-c-x-y-zі p-q-x-y-z. шлях першого вказівника a,b,c,x,y,z,p,q,x, шлях другого вказівникаp,q,x,y,z,a,b,c,x
Микола Голуб

14
Блискуча. Для тих, хто не зрозумів, порахуйте кількість пройдених вузлів від head1-> tail1 -> head2 -> точка перетину та head2 -> tail2-> head1 -> точка перетину. Обидва будуть рівними (намалюйте різні типи зв'язаних списків, щоб підтвердити це). Причина в тому, що обидва вказівника повинні пройти однакові відстані head1-> IP + head2-> IP, перш ніж знову досягти IP. Тож до моменту досягнення IP, обидва вказівника будуть рівними, і у нас є точка злиття.
adev

91

Відповідь Павла вимагає зміни списків , а також повторення кожного списку двічі.

Ось рішення , яке тільки вимагає ітерацію кожного списку двічі (в перший раз , щоб обчислити їх довжину, якщо довжина дається вам потрібно всього лише один раз ітерація).

Ідея полягає в тому, щоб ігнорувати початкові записи більш тривалого списку (точка злиття не може бути там), щоб два вказівники були на рівній відстані від кінця списку. Потім перемістіть їх вперед, поки вони не злиться.

lenA = count(listA) //iterates list A
lenB = count(listB) //iterates list B

ptrA = listA
ptrB = listB

//now we adjust either ptrA or ptrB so that they are equally far from the end
while(lenA > lenB):
    ptrA = ptrA->next
    lenA--
while(lenB > lenA):
    prtB = ptrB->next
    lenB--

while(ptrA != NULL):
    if (ptrA == ptrB):
        return ptrA //found merge point
    ptrA = ptrA->next
    ptrB = ptrB->next

Це асимптотично те саме (лінійний час), як і в моїй іншій відповіді, але, ймовірно, має менші постійні, тому, ймовірно, швидше. Але я думаю, що моя інша відповідь крутіша.


4
Сьогодні, коли ми пили горілку, я запропонував це питання моєму другові, і він дав таку ж відповідь, як і ваш, і попросив опублікувати його на SO. Але ти, здається, першим. Тож я зроблю для вас +1 і хочу, щоб я міг зробити ще +1.
П Швед

2
+1, як це, а також не потребує будь-яких модифікацій списку, також більшість реалізацій пов'язаного списку зазвичай передбачають довжину
keshav84

3
У нас занадто багато Павлів. Моє рішення не потребує зміни списку.
Павло Радзівіловський

Хороша відповідь. Яка часова складність для цього, хоча. 0 (n + m)? де n = вузли у списку 1, m = вузли у списку 2?
Віхаан Верма

замість переміщення обох покажчиків в обох списках: ми можемо просто побачити, якщо diff> = small з двох контурів, якщо так, то перемістимось у малому списку за малим значенням, ще рухаємося у малому списку на значення diff + 1; якщо diff 0, то відповідь останній вузол.
Вішал Ананд

30

Добре, якщо ви знаєте, що вони злиються:

Скажіть, ви починаєте з:

A-->B-->C
        |
        V
1-->2-->3-->4-->5

1) Перейдіть через перший список, встановивши кожен наступний вказівник на NULL.

Тепер у вас є:

A   B   C

1-->2-->3   4   5

2) Тепер перейдіть через другий список і почекайте, поки ви побачите NULL, тобто ваш пункт злиття.

Якщо ви не можете бути впевнені, що вони зливаються, ви можете використовувати значення дозорного для значення вказівника, але це не так елегантно.


3
Однак ви знищуєте цей список у процесі, який більше не використовуватимете: P
Кайл Розендо,

@Kyle Rozendo, добре, моє рішення змінює списки в тому, як вони можуть бути відновлені після обробки. Але це більш чітка демонстрація концепції
П Швед

Я не бачив, щоб зміни списку не були дозволені. Я подумаю, але нічого не спадає на думку, не зберігаючи кожен побачений вузол.
tster

10
Давай, це правильна відповідь! Нам просто потрібно відкоригувати питання :)
П Швед

23
Відмінний алгоритм для створення витоків пам'яті.
Каролі Горват

14

Якщо ми могли б повторити списки рівно вдвічі, то я можу запропонувати метод визначення точки злиття:

  • повторіть обидва списки та обчисліть довжини A і B
  • обчислити різницю довжин C = | AB |;
  • почніть ітерацію обох списків одночасно, але зробіть додаткові C кроки у списку, який був більшим
  • ці два покажчики зустрінуть один одного в точці злиття

8

Ось рішення, обчислювально швидке (повторює кожен список один раз), але використовує багато пам'яті:

for each item in list a
  push pointer to item onto stack_a

for each item in list b
  push pointer to item onto stack_b

while (stack_a top == stack_b top) // where top is the item to be popped next
  pop stack_a
  pop stack_b

// values at the top of each stack are the items prior to the merged item

2
Це еквівалент обробки списку двічі.
Георг Шоллі

Я припускаю, що технічно ви займаєтесь списками двічі, але це суттєве вдосконалення рішення Кайла Розендо. Тепер, якщо "обробка списку" визначається як "читання значення посилання та наступний за вказівником", можна стверджувати, що він обробляє список один раз - він зчитує кожне значення посилання один раз, зберігає його та потім порівнює їх.
Skizz

Безумовно, буде швидше, ніж у мене, без сумніву.
Кайл Розендо

7

Можна використовувати набір Вузлів. Ітерація через один список та додавання кожного вузла до набору. Потім повторіть другий список і для кожної ітерації перевірте, чи існує Вузол у наборі. Якщо це так, ви знайшли свою точку злиття :)


Боюся (через додатковий простір Ω (n)) це єдиний підхід (а не відновлення переліку списків) і не розбір списку більше одного разу. Виявлення циклу в списку тривіально для першого списку (перевірте, чи вузол у наборі) - використовуйте будь-який метод виявлення циклу у другому списку для забезпечення припинення. (Питання для інтерв'ю, можливо , стосувалося уважного прослуховування проблеми, і не вскакуючи, щоб скористатися молотком. Ви,
напевно,

6

Це, безсумнівно, порушує умову "розбирати кожен список лише один раз", але впроваджує алгоритм черепахи та зайця (використовується для пошуку точки злиття та довжини циклу циклічного списку), тому ви починаєте зі списку А, і коли доходите до NULL у наприкінці ви робите вигляд, що це вказівник на початок списку B, створюючи таким чином вигляд циклічного списку. Тоді алгоритм точно скаже вам, наскільки далеко знаходиться злиття Список А (змінна 'mu' згідно опису Вікіпедії).

Також значення "лямбда" повідомляє вам довжину списку B, і якщо ви хочете, ви можете розробити довжину списку А під час роботи алгоритму (коли ви перенаправляєте посилання NULL).


Досить багато того, що я сказав, просто з модних імен. : P
Кайл Розендо

Зовсім ні. Це рішення - O (n) в операціях і O (1) у використанні пам'яті (насправді потрібні лише дві змінні вказівника).
Артелій

Так, слід було видалити попередній коментар, оскільки моє рішення трохи змінилося. Хе-хе.
Кайл Розендо

Але я не бачу, як це було застосовано в першу чергу?
Артелій

Ваше пояснення зробив, а не сам алгоритм. Можливо, я бачу це інакше, але так.
Кайл Розендо

3

Можливо, я над цим спрощую, але просто повторюю найменший список і використовую останні вузли Linkяк точку злиття?

Отже, де Data->Link->Link == NULLє кінцева точка, даючи Data->Linkяк точку злиття (в кінці списку).

Редагувати:

Гаразд, з картинки, яку ви опублікували, ви розбираєте два списки, найменший перший. За допомогою найменшого списку ви можете підтримувати посилання на наступний вузол. Тепер, коли ви аналізуєте другий список, ви робите порівняння посилання, щоб знайти, де Reference [i] є посиланням на LinkedList [i] -> Посилання. Це дасть точку злиття. Час пояснити картинками (накладіть значення на малюнок ОП).

У вас пов'язаний список (посилання наведені нижче):

A->B->C->D->E

У вас є другий зв'язаний список:

1->2->

При злитому списку посилання йдуть наступним чином:

1->2->D->E->

Тому ви картографуєте перший "менший" список (оскільки об'єднаний список, який ми підраховуємо, має довжину 4 і основний список 5)

Проведіть цикл через перший список, підтримуйте посилання на посилання.

Список буде містити наступні посилання Pointers { 1, 2, D, E }.

Зараз ми проходимо через другий список:

-> A - Contains reference in Pointers? No, move on
-> B - Contains reference in Pointers? No, move on
-> C - Contains reference in Pointers? No, move on
-> D - Contains reference in Pointers? Yes, merge point found, break.

Звичайно, ви підтримуєте новий список покажчиків, але це не виходить за межі специфікації. Однак перший список аналізується рівно один раз, а другий список буде повністю розібраний лише тоді, коли немає точки злиття. В іншому випадку воно закінчиться швидше (у точці злиття).


Ну дещо змінюється від того, що я хотів спочатку сказати, але від того, що, здається, хоче ОП, це зробить трюк.
Кайл Розендо

Зараз зрозуміліше. Але лінійний у використанні пам'яті. Мені це не подобається.
Артелій

Питання не вимагало більше, інакше весь процес може бути багатопоточним. Це все ще спрощений вигляд рішення "верхнього рівня", код може бути реалізований будь-якою кількістю способів. :)
Кайл Розендо

1
Ага, що? Багатопотокове читання - це спосіб кращого використання процесорної потужності, а не зменшення загальної потужності процесора, який вимагає алгоритм. І сказати, що код можна реалізувати будь-якою кількістю способів - це лише привід.
Артелій

1
Це дійсно згинає "розбір кожного списку лише один раз" до точки перелому. Все, що ви робите, - це скопіювати один список, а потім перевірити інший список проти його копії.
Skizz

3

Я перевірив випадок злиття на моєму FC9 x86_64 і друкую кожну адресу вузла, як показано нижче:

Head A 0x7fffb2f3c4b0
0x214f010
0x214f030
0x214f050
0x214f070
0x214f090
0x214f0f0
0x214f110
0x214f130
0x214f150
0x214f170


Head B 0x7fffb2f3c4a0
0x214f0b0
0x214f0d0
0x214f0f0
0x214f110
0x214f130
0x214f150
0x214f170

Зверніть увагу на те, що я вирівняв структуру вузла, тому коли malloc () вузол, адресу вирівнюється з 16 байтами, див. Принаймні 4 біти. Найменше бітів дорівнює 0s, тобто 0x0 або 000b. Тож якщо ви також знаходитесь у тому самому спеціальному випадку (вирівняна адреса вузла), ви можете використовувати ці мінімум 4 біти. Наприклад, пересуваючи обидва списки від голови до хвоста, встановіть 1 або 2 з 4 біт адреси відвідуючого вузла, тобто встановіть прапор;

next_node = node->next;
node = (struct node*)((unsigned long)node | 0x1UL);

Зауважте, що вище прапорів не впливатиме на реальну адресу вузла, а лише на значення ВКАЗАНОГО вузла.

Як тільки хтось знайшов, хто встановив біт (и) прапора, то першим знайденим вузлом має бути точка злиття. після завершення ви відновите адресу вузла, очистивши встановлені біти прапора. хоча важлива річ, що вам слід бути обережними, коли ітерація (наприклад, node = node-> next) чистить. пам’ятайте, що ви встановили біти прапора, так чиніть так

real_node = (struct node*)((unsigned long)node) & ~0x1UL);
real_node = real_node->next;
node = real_node;

Оскільки ця пропозиція відновить змінені адреси вузлів, це може розглядатися як "без змін".


+1, це те, що природно приходить в голову з "повтором лише один раз", не знаю, чому це ніколи не проголосували! Прекрасне рішення.
jman

3

Тут може бути просте рішення, але знадобиться допоміжний простір. Ідея полягає в тому, щоб переглядати список і зберігати кожну адресу на хеш-карті, тепер перейдіть за іншим списком і збіжіться, якщо адреса лежить у хеш-карті чи ні. Кожен список проходить лише один раз. Немає змін до жодного списку. Довжина досі невідома. Використовуваний допоміжний простір: O (n), де 'n' - довжина пройденого першого списку.


2

це рішення повторює кожен список лише один раз ... також не потрібно змінювати список. Хоча ви можете скаржитися на простір ..
1) В основному ви повторюєте список1 і зберігаєте адресу кожного вузла в масиві (який зберігає неподписане значення int)
2) Потім ви повторюєте list2, і для адреси кожного вузла ---> ви шукаєте через масив, який ви знайшли відповідність чи ні ... якщо ви це зробите, то це вузол, що зливається

//pseudocode
//for the first list
p1=list1;
unsigned int addr[];//to store addresses
i=0;
while(p1!=null){
  addr[i]=&p1;
  p1=p1->next;
}
int len=sizeof(addr)/sizeof(int);//calculates length of array addr
//for the second list
p2=list2;
while(p2!=null){
  if(search(addr[],len,&p2)==1)//match found
  {
    //this is the merging node
    return (p2);
  }
  p2=p2->next;
}

int search(addr,len,p2){
  i=0;  
  while(i<len){
    if(addr[i]==p2)
      return 1;
    i++;
  }
 return 0;
} 

Сподіваюся, це правильне рішення ...


Це майже повторює один із списків не один раз, хоча у вигляді масиву замість самого списку.
syockit

1

Не потрібно змінювати жоден список. Є рішення, в якому нам залишається пройти кожен список лише один раз.

  1. Створіть два стеки, скажімо, stck1 та stck2.
  2. Прокрутіть 1-й список і натисніть на копію кожного вузла, який ви проходите в stck1.
  3. Так само, як другий крок, але на цей раз пройдіть другий список і натисніть на копію вузлів у stck2.
  4. Тепер вискочіть з обох стеків і перевірте, чи рівні два вузли рівні, якщо так, то збережіть посилання на них. Якщо ні, то попередні вузли, які були рівними, - це насправді точка злиття, яку ми шукали.

1
int FindMergeNode(Node headA, Node headB) {
  Node currentA = headA;
  Node currentB = headB;

  // Do till the two nodes are the same
  while (currentA != currentB) {
    // If you reached the end of one list start at the beginning of the other
    // one currentA
    if (currentA.next == null) {
      currentA = headA;
    } else {
      currentA = currentA.next;
    }
    // currentB
    if (currentB.next == null) {
      currentB = headB;
    } else {
      currentB = currentB.next;
    }
  }
  return currentB.data;
}

У своєму первісному перегляді це лише прописало найвищу відповідь (Павло Радзівіловський, 2013) .
сіра борода

0

Ось наївне рішення, Не потрібно переходити цілі списки.

якщо ваш структурований вузол має три схожі поля

struct node {
    int data;   
    int flag;  //initially set the flag to zero  for all nodes
    struct node *next;
};

скажімо, у вас дві голови (head1 та head2), що вказують на голову двох списків.

Перемістіть обидва списки в одному темпі та поставте прапор = 1 (відвіданий прапор) для цього вузла,

  if (node->next->field==1)//possibly longer list will have this opportunity
      //this will be your required node. 

0

Як щодо цього:

  1. Якщо вам дозволено проходити кожен список лише один раз, ви можете створити новий вузол, пройдіть перший список, щоб мати кожну точку вузла до цього нового вузла, і пройдіть другий список, щоб побачити, чи будь-який вузол вказує на ваш новий вузол ( це ваша точка злиття). Якщо другий обхід не веде до вашого нового вузла, то в оригінальних списках немає точки злиття.

  2. Якщо вам дозволяється пересувати списки не один раз, ви можете пройти кожен список, щоб знайти їх довжину, і якщо вони різні, опустіть "зайві" вузли на початку більш тривалого списку. Потім просто пройдіть обидва списки по одному кроці за одним і знайдіть перший вузол, що об’єднується.


1. не тільки модифікує, але знищує перший список. 2. пропонується раз і знову.
сіра борода

0

Кроки на Java:

  1. Створіть карту.
  2. Почніть проїзд в обох гілках списку та введіть усі пройдені вузли списку на карту, використовуючи унікальну річ, пов’язану з Вузлами (скажімо, ідентифікатором вузла), як Ключ, а Значення - 1 на початку для всіх.
  3. Коли коли-небудь приходить перший дублікат ключа, збільшуйте значення для цього ключа (скажімо, тепер його значення стало 2, яке> 1.
  4. Отримайте ключ, де значення більше 1, і це повинен бути вузол, де два списки зливаються.

1
Що робити, якщо у нас є об'єднаний цикл?
Рохіт

Але для циклів обробки помилок це дуже схоже на відповідь isyi .
сіра борода

0

Ми можемо ефективно вирішити це, ввівши поле "isVited". Перемістіть перший список і встановіть значення "isVisited" на "true" для всіх вузлів до кінця. Тепер почніть з другого і знайдіть перший вузол, де прапор істинний і Boom, його ваша точка злиття.


0

Крок 1: знайдіть довжину обох списків. Крок 2: Знайдіть різницю та перемістіть найбільший список із різницею. Крок 3: Тепер обидва списки будуть у подібному положенні. Крок 4: Ітерація через список, щоб знайти точку злиття

//Psuedocode
def findmergepoint(list1, list2):
lendiff = list1.length() > list2.length() : list1.length() - list2.length() ? list2.lenght()-list1.lenght()
biggerlist = list1.length() > list2.length() : list1 ? list2  # list with biggest length
smallerlist = list1.length() < list2.length() : list2 ? list1 # list with smallest length


# move the biggest length to the diff position to level both the list at the same position
for i in range(0,lendiff-1):
    biggerlist = biggerlist.next
#Looped only once.  
while ( biggerlist is not None and smallerlist is not None ):
    if biggerlist == smallerlist :
        return biggerlist #point of intersection


return None // No intersection found

(Мені сподобався список, коли кожен елемент починає лінійку краще. Подумайте про перевірку орфографії.)
сіра борода

0
int FindMergeNode(Node *headA, Node *headB)
{
    Node *tempB=new Node;
    tempB=headB;
   while(headA->next!=NULL)
       {
       while(tempB->next!=NULL)
           {
           if(tempB==headA)
               return tempB->data;
           tempB=tempB->next;
       }
       headA=headA->next;
       tempB=headB;
   }
    return headA->data;
}

Вам потрібно додати трохи пояснень до своєї відповіді. Відповіді з коду можуть бути видалені.
rghome

0

Використовуйте карту або словник для зберігання адреси та значення вузла. якщо в карті / словнику є адреса, то значенням ключа є відповідь. Я зробив це:

int FindMergeNode(Node headA, Node headB) {

Map<Object, Integer> map = new HashMap<Object, Integer>();

while(headA != null || headB != null)
{
    if(headA != null && map.containsKey(headA.next))
    {
        return map.get(headA.next);
    }

    if(headA != null && headA.next != null)
    {
         map.put(headA.next, headA.next.data);
         headA = headA.next;
    }

    if(headB != null && map.containsKey(headB.next))
    {
        return map.get(headB.next);
    }

    if(headB != null && headB.next != null)
    {
        map.put(headB.next, headB.next.data);
        headB = headB.next;
    }
}

return 0;
}

0

Рішення складності AO (n). Але виходячи з припущення.

припущення таке: обидва вузли мають лише додатні цілі числа.

логіка: зробіть усе ціле число list1 до мінус. Потім пройдіть список2, поки не отримаєте від’ємне ціле число. Як тільки знайдете => візьміть його, змініть знак на позитивний і поверніться.

static int findMergeNode(SinglyLinkedListNode head1, SinglyLinkedListNode head2) {

    SinglyLinkedListNode current = head1; //head1 is give to be not null.

    //mark all head1 nodes as negative
    while(true){
        current.data = -current.data;
        current = current.next;
        if(current==null) break;
    }

    current=head2; //given as not null
    while(true){
        if(current.data<0) return -current.data;
        current = current.next;
    }

}

0

Ми можемо використовувати два покажчики і рухатися таким чином, що якщо один з покажчиків є нульовим, ми вказуємо його на голову іншого списку і те саме для іншого, таким чином, якщо довжина списку буде різною, вони зустрінуться у другому проході . Якщо довжина list1 дорівнює n, а list2 - m, їх різниця d = abs (nm). Вони пройдуть цю відстань і зустрінуться в точці злиття.
Код:

int findMergeNode(SinglyLinkedListNode* head1, SinglyLinkedListNode* head2) {
    SinglyLinkedListNode* start1=head1;
    SinglyLinkedListNode* start2=head2;
    while (start1!=start2){
        start1=start1->next;
        start2=start2->next;
        if (!start1)
        start1=head2;
        if (!start2)
        start2=head1;
    }
    return start1->data;
}

0

Ви можете додати вузли list1до хеш-версії та циклу через другий, і якщо який-небудь вузол list2вже присутній у наборі. Якщо так, то це вузол злиття

static int findMergeNode(SinglyLinkedListNode head1, SinglyLinkedListNode head2) {
    HashSet<SinglyLinkedListNode> set=new HashSet<SinglyLinkedListNode>();
    while(head1!=null)
    {
        set.add(head1);
        head1=head1.next;
    }
    while(head2!=null){
        if(set.contains(head2){
            return head2.data;
        }
    }
    return -1;
}

0

Рішення за допомогою JavaScript

var getIntersectionNode = function(headA, headB) {
    
    if(headA == null || headB == null) return null;
    
    let countA = listCount(headA);
    let countB = listCount(headB);
    
    let diff = 0;
    if(countA > countB) {

        diff = countA - countB;
        for(let i = 0; i < diff; i++) {
            headA = headA.next;
        }
    } else if(countA < countB) {
        diff = countB - countA;
        for(let i = 0; i < diff; i++) {
            headB = headB.next;
        }
    }

    return getIntersectValue(headA, headB);
};

function listCount(head) {
    let count = 0;
    while(head) {
        count++;
        head = head.next;
    }
    return count;
}

function getIntersectValue(headA, headB) {
    while(headA && headB) {
        if(headA === headB) {
            return headA;
        }
        headA = headA.next;
        headB = headB.next;
    }
    return null;
}

0

Якщо редагування пов'язаного списку дозволено,

  1. Потім просто зробіть наступний покажчик вузла всіх вузлів списку 2 як нульовий.
  2. Знайдіть значення даних останнього вузла списку 1. Це дасть вам пересічний вузол в одному переході обох списків, без "логіки привіт".
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.