Bağlı iki listenin birleşip birleşmediğini kontrol edin. Öyleyse nerede?


102

Bu soru eski olabilir ama bir cevap düşünemedim.

Diyelim ki, bir noktada birleşen farklı uzunluklarda iki liste var ; birleşme noktasının nerede olduğunu nasıl bileceğiz?

Koşullar:

  1. Uzunluğu bilmiyoruz
  2. Her listeyi yalnızca bir kez ayrıştırmalıyız.

Birleştirilmiş bağlantılı iki liste örneği.


birleştirme, bu noktadan itibaren yalnızca bir liste olacağı anlamına gelir.
rplusg

Listenin değiştirilmesine izin veriliyor mu?
Artelius

1
Listede değişiklik yapılmadan çalışmayacağından oldukça eminim. (Ya da sadece bir kez ayrıştırma kısıtlamasından kaçınmak için başka bir yere kopyalamak.)
Georg Schölly

2
Konu bu olabilir. Kahrolası görüşmeciler! Hehe
Kyle Rosendo

1
Listenin ortak kuyruğunun sonsuz uzunlukta olduğunu varsayarak ilginç bir önerim var. Sabit belleği kullanarak düğüm kesişimini nasıl bulabilirsiniz?
Akusete

Yanıtlar:


36

Eğer

  • "Değişikliğe izin verilmez" ifadesi, "değiştirebilirsiniz ancak sonunda geri yüklenmeleri gerekir" anlamına gelmektedir ve
  • listeleri tam olarak iki kez yineleyebiliriz

Aşağıdaki algoritma çözüm olacaktır.

Önce sayılar. İlk listenin uzunlukta a+cve ikinci listenin uzunlukta olduğunu varsayın b+c, burada cortak "kuyruk" unun uzunluğu (birleşme noktasından sonra). Bunları şu şekilde gösterelim:

x = a+c
y = b+c

Biz uzunluğunu bilmiyorum yana, hesaplar xve yek tekrarlamalar olmadan; nasıl olduğunu göreceksin.

Ardından, her listeyi yineler ve yinelerken tersine çeviririz! Her iki yineleyici de birleştirme noktasına aynı anda ulaşırsa, bunu yalnızca karşılaştırma yaparak buluruz. Aksi takdirde, bir işaretçi diğerinden önce birleştirme noktasına ulaşacaktır.

Bundan sonra, diğer yineleyici birleştirme noktasına ulaştığında, ortak kuyruğa ilerlemeyecektir. Bunun yerine, daha önce birleşme noktasına ulaşan listenin eski başlangıcına geri dönecektir! Dolayısıyla, değiştirilen listenin sonuna (yani diğer listenin önceki başlangıcına) ulaşmadan önce, a+b+1toplam yinelemeleri yapacaktır . Hadi diyelim z+1.

İlk olarak birleştirme noktasına ulaşan işaretçi, listenin sonuna ulaşıncaya kadar yinelemeye devam edecektir. Yaptığı yineleme sayısı hesaplanmalı ve eşittir x.

Ardından, bu işaretçi geri döner ve listeleri yeniden tersine çevirir. Ama şimdi başlangıçta başladığı listenin başına dönmeyecek! Bunun yerine, diğer listenin başına gidecek! Yaptığı yineleme sayısı hesaplanmalı ve eşit olmalıdır y.

Yani aşağıdaki sayıları biliyoruz:

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

Bunu belirlediğimiz

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

Sorunu çözen.


2
Soru durumlarına açıklama, listenin değiştirilmesine izin verilmez!
Skizz

1
Bu cevabı beğendim (çok yaratıcı). Bununla ilgili tek sorunum, her iki listenin uzunluğunu bildiğinizi varsayması.
tster

listeyi değiştiremezsiniz ve uzunluğunu bilmiyoruz - bunlar kısıtlamalar ... her nasılsa, yaratıcı bir cevap için teşekkürler.
rplusg

2
@tster, @calvin, cevap varsayılmıyor, uzunluğa ihtiyacımız var. Satır içi olarak hesaplanabilir. Cevaplarıma açıklamalar ekliyorum.
P Shved

2
@Forethinker ziyaret edilen düğümlere hashing uygulamak ve / veya bunları görüldüğü gibi işaretlemek O (liste uzunluğu) belleği gerektirirken, birçok çözüm (benimki dahil, ancak kusurlu ve karmaşık olsa da) O (1) bellek gerektirir.
P Shved

159

Aşağıdakiler, gördüğüm her şeyin en büyüğü - O (N), sayaç yok. SN adayıyla bir röportaj sırasında aldım:VisionMap'te .

Şunun gibi araya giren bir işaretçi yapın: sonuna kadar her defasında ileri gider ve sonra karşı listenin başına atlar, vb. İki kafayı göstererek bunlardan iki tane oluşturun. İşaretçilerin her birini buluşana kadar her seferinde 1 artırın. Bu, bir veya iki geçişten sonra gerçekleşir.

Bu soruyu görüşmelerde hala kullanıyorum - ancak birinin bu çözümün neden işe yaradığını anlamasının ne kadar sürdüğünü görmek için.


6
bu harika!
Cong Hui

2
Bu iyi bir cevap, ancak 2 numaralı koşulu ihlal eden listeleri iki kez gözden geçirmelisiniz.
tster

2
Bir birleştirme noktasının mevcut olması garanti edilirse, bu çözümü oldukça zarif buluyorum. Birleştirme noktalarını algılamak için çalışmaz, sanki biri yokmuş gibi sonsuz döngüye girer.
alternatif yön

4
Bu çok zekice! Açıklama: 2 listemiz var: a-b-c-x-y-zve p-q-x-y-z. ilk işaretçinin a,b,c,x,y,z,p,q,xyolu, ikinci işaretçinin yolup,q,x,y,z,a,b,c,x
Nikolai Golub

14
Parlak. Anlamayanlar için, head1-> tail1 -> head2 -> kesişme noktası ve head2 -> tail2-> head1 -> kesişme noktasından gidilen düğüm sayısını sayın. Her ikisi de eşit olacaktır (Bunu doğrulamak için bağlantılı listelerin farklı türlerini çizin). Bunun nedeni, her iki işaretçinin tekrar IP'ye ulaşmadan önce head1-> IP + head2-> IP ile aynı mesafeleri kat etmesi gerektiğidir. Yani IP'ye ulaştığında, her iki işaretçi de eşit olacak ve birleşme noktasına sahip olacağız.
adev

91

Pavel'in cevabı, listelerin yanı sıra iki kez her liste yineleme.

İşte her listeyi yalnızca iki kez yinelemeyi gerektiren bir çözüm (uzunluklarını ilk kez hesaplamak için; uzunluk verilirse yalnızca bir kez yinelemeniz gerekir).

Buradaki fikir, uzun listenin başlangıç ​​girişlerini yok saymaktır (birleştirme noktası orada olamaz), böylece iki işaretçi listenin sonundan eşit uzaklıkta olur. Sonra birleşene kadar ileriye doğru hareket ettirin.

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

Bu, diğer cevabımla asimptotik olarak aynıdır (doğrusal zaman), ancak muhtemelen daha küçük sabitlere sahiptir, bu nedenle muhtemelen daha hızlıdır. Ama diğer cevabımın daha havalı olduğunu düşünüyorum.


4
Bugün votka içerken, bu soruyu bir arkadaşıma önerdim ve seninle aynı cevabı verdi ve SO'da yayınlamasını istedi. Ama ilk görünüyorsun. Bu yüzden benden sizin için +1 yapacağım ve keşke başka bir +1 yapabilseydim.
P Shved

2
+1 bunun gibi ve listede herhangi bir değişikliğe ihtiyaç duymaz, ayrıca bağlantılı liste uygulamalarının çoğu genellikle uzunluk sağlar
keshav84

3
Çok fazla Pavelimiz var. Çözümüm listeyi değiştirmeyi gerektirmiyor.
Pavel Radzivilovsky

İyi cevap. Bunun için zaman karmaşıklığı ne olacak. 0 (n + m)? burada n = liste 1'deki düğümler, m = liste 2'deki düğümler?
Vihaan Verma

her iki listedeki her iki işaretleyiciyi de taşımak yerine: sadece diff> = iki yolun küçük olup olmadığını görebiliriz, eğer öyleyse, küçük listede küçük bir değere göre hareket ederse, küçük listede diff + 1 değerine göre hareket edebiliriz; diff 0 ise son düğüm cevaptır.
Vishal Anand

30

Peki, birleşeceklerini biliyorsanız:

Şöyle başladığını söyle:

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

1) Her bir sonraki işaretçiyi NULL olarak ayarlayan ilk listeden geçin.

Şimdi sahipsin:

A   B   C

1-->2-->3   4   5

2) Şimdi ikinci listeye geçin ve bir NULL görene kadar bekleyin, bu sizin birleştirme noktanızdır.

Birleştiklerinden emin olamıyorsanız, işaretçi değeri için bir gözcü değeri kullanabilirsiniz, ancak bu o kadar zarif değildir.


4
Ancak, bu işlem sırasında listeyi yok edersiniz, bir daha asla kullanılmazsınız: P
Kyle Rosendo

@Kyle Rozendo, benim çözümüm listeleri işlendikten sonra geri yüklenebilecekleri şekilde değiştiriyor. Ancak bu, konseptin daha net bir göstergesidir
P Shved

Listede değişiklik yapılmasına izin verilmediğini görmedim. Bir düşüneceğim ama görülen her düğümü saklamadan aklıma hiçbir şey gelmiyor.
tster

10
Hadi, bu doğru cevap! Sadece soruyu değiştirmemiz gerekiyor :)
P Shved

24
Bellek sızıntıları oluşturmak için mükemmel algoritma.
Karoly Horvath

14

Listeleri tam olarak iki kez yineleyebilseydik, birleştirme noktasını belirlemek için bir yöntem sağlayabilirim:

  • hem listeyi yineleyin hem de A ve B uzunluklarını hesaplayın
  • uzunluk farkını hesaplayın C = | AB |;
  • her iki listeyi aynı anda yinelemeye başlayın, ancak listede daha büyük olan ek C adımlarını yapın
  • bu iki işaretçi birleşme noktasında buluşacak

8

İşte bir çözüm, hesaplama açısından hızlı (her listeyi bir kez yineliyor) ancak çok fazla bellek kullanıyor:

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
Bu, bir listeyi iki kez işlemenin karşılığıdır.
Georg Schölly

Sanırım teknik olarak listelerle iki kez çalışıyorsunuz, ancak bu Kyle Rozendo'nun çözümünde önemli bir gelişme. Şimdi, 'listeyi işlemek', 'bağlantı değerini okumak ve işaretçiyi takip etmek' olarak tanımlanırsa, listeyi bir kez işlediği söylenebilir - her bir bağlantı değerini bir kez okur, saklar ve sonra karşılaştırır.
Skizz

Kesinlikle benimkinden daha hızlı olacak, şüphesiz.
Kyle Rosendo

7

Bir dizi Düğüm kullanabilirsiniz. Bir listeyi yineleyin ve her Düğümü kümeye ekleyin. Ardından ikinci listeyi yineleyin ve her yinelemede düğümün kümede olup olmadığını kontrol edin. Varsa, birleştirme noktanızı buldunuz :)


Korkarım (Ω (n) ek alan nedeniyle) bu tek yaklaşımdır (listeyi / listeleri yeniden oluşturmak ve) bir listeyi birden fazla ayrıştırmamak. Listedeki bir döngüyü saptamak ilk liste için önemsizdir (düğümün kümede olup olmadığını kontrol edin) - sonlandırmayı sağlamak için ikinci listedeki herhangi bir döngü algılama yöntemini kullanın. (Mülakat sorusu olabilir dinleme hakkında olmuştur dikkatlice bir sorun açıklamaya ve değil sen isabet şey değil uzunca bir çivi bilmek ne bir çekiç kullanmak için atlama.)
ihtiyar adam

6

Bu muhtemelen "her listeyi yalnızca bir kez ayrıştır" koşulunu ihlal eder, ancak kaplumbağa ve tavşan algoritmasını (döngüsel bir listenin birleştirme noktasını ve döngü uzunluğunu bulmak için kullanılır) uygular, böylece Liste A'dan başlarsınız ve NULL'a ulaştığınızda end B listesinin başlangıcına bir gösterici gibi davranırsınız, böylece döngüsel bir liste görünümü yaratırsınız. Ardından algoritma size A Listesinin tam olarak ne kadar aşağıda olduğunu söyleyecektir (Wikipedia açıklamasına göre 'mu' değişkeni).

Ayrıca, "lambda" değeri size B listesinin uzunluğunu söyler ve isterseniz, algoritma sırasında (NULL bağlantısını yeniden yönlendirdiğinizde) A listesinin uzunluğunu hesaplayabilirsiniz.


Söylediklerimin çoğu, sadece meraklı isimlerle. : P
Kyle Rosendo

Bir şey değil. Bu çözüm, işlemlerde O (n) ve bellek kullanımında O (1) 'dir (aslında sadece iki işaret değişkeni gerektirir).
Artelius

Evet, çözümüm biraz değiştiği için önceki yorumumu silmeliydim. Hehe.
Kyle Rosendo

Ama ilk başta bunun nasıl uygulanabilir olduğunu anlamıyorum?
Artelius

Sizin açıklamanız, algoritmanın kendisi değil. Belki ben farklı bakıyorum ama hey.
Kyle Rosendo

3

Belki bunu fazla basitleştiriyorum, ancak en küçük listeyi yineleyin ve son düğümleri Linkbirleşme noktası olarak kullanın.

Öyleyse, Data->Link->Link == NULLbitiş noktası nerede , Data->Linkbirleşme noktası olarak (listenin sonunda) verilir.

DÜZENLE:

Tamam, gönderdiğiniz resimden, en küçüğü ilk olmak üzere iki listeyi ayrıştırırsınız. En küçük liste ile aşağıdaki düğüme referansları koruyabilirsiniz. Şimdi, ikinci listeyi ayrıştırdığınızda, Referans [i] 'nin LinkedList [i] -> Link'teki referans olduğunu bulmak için referans üzerinde bir karşılaştırma yaparsınız. Bu, birleştirme noktasını verecektir. Resimlerle açıklama zamanı (değerleri resimdeki OP üzerine yerleştirin).

Bağlantılı bir listeniz var (aşağıda gösterilen referanslar):

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

İkinci bir bağlantılı listeniz var:

1->2->

Birleştirilmiş listeyle, referanslar şu şekilde olacaktır:

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

Bu nedenle, ilk "daha küçük" listeyi eşlersiniz (bizim saydığımız birleştirilmiş listenin uzunluğu 4 ve ana liste 5 olduğu için)

İlk listede döngü yapın, referansların referansını koruyun.

Liste aşağıdaki referansları içerecektir Pointers { 1, 2, D, E }.

Şimdi ikinci listeye geçiyoruz:

-> 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.

Elbette, yeni bir işaretçiler listesi tutuyorsunuz, ancak bu spesifikasyonun dışında değil. Bununla birlikte, ilk liste tam olarak bir kez ayrıştırılır ve ikinci liste yalnızca bir birleştirme noktası yoksa tam olarak ayrıştırılır. Aksi takdirde, daha erken biter (birleştirme noktasında).


İlk başta söylemek istediklerimden biraz değişiyor, ancak OP'nin istediği gibi, bu işe yarayacak.
Kyle Rosendo

Şimdi daha net. Ancak bellek kullanımında doğrusal. Bundan hoşlanmadım
Artelius

Soru daha fazlasını istemedi, aksi takdirde tüm süreç çok iş parçacıklı olabilir. Bu hala çözümün basit bir "üst düzey" görünümüdür, kod herhangi bir şekilde uygulanabilir. :)
Kyle Rosendo

1
Ah ne? Çoklu okuma, bir algoritmanın gerektirdiği toplam işlem gücünü düşürmek yerine, işlem gücünü daha iyi kullanmanın bir yoludur. Ve kodun herhangi bir şekilde uygulanabileceğini söylemek sadece bir bahanedir.
Artelius

1
Bu, "her listeyi yalnızca bir kez ayrıştır" seçeneğini gerçekten kırılma noktasına yaklaştırır. Tek yaptığınız, bir listeyi kopyalamak ve ardından diğer listeyi kopyayla karşılaştırmaktır.
Skizz

3

FC9 x86_64 cihazımda bir birleştirme durumunu test ettim ve her düğüm adresini aşağıda gösterildiği gibi yazdırdım:

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


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

Düğüm yapısını hizaladığıma dikkat edin, bu nedenle malloc () bir düğüm olduğunda, adres 16 bayt ile hizalanır, bkz. En az 4 bit. En küçük bitler 0'dır, yani 0x0 veya 000b. Yani siz de aynı özel durumdaysanız (hizalanmış düğüm adresi), bu en az 4 biti kullanabilirsiniz. Örneğin, her iki listeyi de baştan sona gezerken, ziyaret düğümü adresinin 4 bitinin 1 veya 2'sini ayarlayın, yani bir bayrak ayarlayın;

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

Yukarıdaki bayraklar gerçek düğüm adresini etkilemez, yalnızca SAVED düğüm işaretçi değerini etkiler.

Birinin bayrak bitlerini ayarladığını bulduktan sonra, bulunan ilk düğüm birleştirme noktası olmalıdır. tamamlandıktan sonra, ayarladığınız bayrak bitlerini temizleyerek düğüm adresini geri yüklersiniz. önemli olan şey ise, temizlik yapmak için yinelediğinizde (örn. düğüm = düğüm-> sonraki) dikkatli olmanız gerektiğidir. bayrak bitleri koyduğunuzu hatırlayın, bu şekilde yapın

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

Bu teklif, değiştirilen düğüm adreslerini geri yükleyeceğinden, "değişiklik yok" olarak kabul edilebilir.


+1, doğal olarak "sadece bir kez yinele" denince akla gelen şey bu, bunun neden hiç oylanmadığını bilmiyorum! Güzel çözüm.
jman

3

Basit bir çözüm olabilir, ancak yardımcı bir alan gerektirecektir. Buradaki fikir, bir listeyi dolaşmak ve her adresi bir hash haritasında saklamak, şimdi diğer listeyi taramak ve adres, karma haritada yer alıp almamaktır. Her liste yalnızca bir kez taranır. Herhangi bir listede değişiklik yok. Uzunluk hala bilinmiyor. Kullanılan yardımcı boşluk: O (n) burada 'n', geçilen ilk listenin uzunluğudur.


2

bu çözüm, her listeyi yalnızca bir kez yineler ... listenin değiştirilmesine de gerek yoktur ... gerçi alan hakkında şikayetçi olabilirsiniz ..
1) Temel olarak liste1'de yinelersiniz ve her düğümün adresini bir dizide saklarsınız (işaretsiz int değerini saklar)
2) Sonra list2'yi yinelersiniz ve her düğümün adresi için ---> bir eşleşme bulup bulmadığınız dizide arama yaparsınız ... Eğer yaparsanız, o zaman bu birleştirme düğümüdür

//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;
} 

Umarım geçerli bir çözümdür ...


Listenin kendisi yerine bir dizi biçiminde olsa da, bu listelerden birini bir kereden fazla yineler.
syockit

1

Herhangi bir listeyi değiştirmeye gerek yoktur. Her listeyi yalnızca bir kez geçmemiz gereken bir çözüm var.

  1. İki yığın oluşturun, stck1 ve stck2 diyelim.
  2. 1. listeyi geçin ve stck1'de gezdiğiniz her düğümün bir kopyasını itin.
  3. İkinci adımla aynı, ancak bu sefer 2. listeyi geçin ve stck2'deki düğümlerin kopyasını itin.
  4. Şimdi, her iki yığıntan da çıkın ve iki düğümün eşit olup olmadığını kontrol edin, eğer öyleyse, onlara bir referans verin. Hayır ise, o zaman eşit olan önceki düğümler aslında aradığımız birleşme noktasıdır.

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;
}

Orijinal revizyonunda, bu sadece en yüksek oyu alan cevabı heceledi (Pavel Radzivilovsky, 2013) .
greybeard

0

İşte saf bir çözüm, tüm listeleri taramaya gerek yok.

yapılandırılmış düğümünüz gibi üç alan varsa

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

iki listenin başına işaret eden iki başınız (başlık1 ve baş2) olduğunu söyleyin.

Her iki listeyi de aynı hızda geçin ve bu düğüm için bayrağı = 1 (ziyaret edilen bayrak) koyun,

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

0

Buna ne dersin:

  1. Her listeyi yalnızca bir kez geçme izniniz varsa, yeni bir düğüm oluşturabilir, her düğüm noktasının bu yeni düğüme gelmesini sağlamak için ilk listeden geçebilir ve herhangi bir düğümün yeni düğümünüzü işaret edip etmediğini görmek için ikinci listeyi geçebilirsiniz ( bu birleştirme noktanız). İkinci geçiş yeni düğümünüze yol açmazsa, orijinal listelerin bir birleştirme noktası yoktur.

  2. Listeleri birden fazla kez gezme izniniz varsa, uzunluklarımızı bulmak için her listeyi gezebilir ve farklılarsa uzun listenin başındaki "ekstra" düğümleri atlayabilirsiniz. Ardından, her iki listeyi bir seferde bir adım öteye taşıyın ve ilk birleştirme düğümünü bulun.


1. sadece ilk listeyi değiştirmez, aynı zamanda yok eder. 2. tekrar tekrar önerilmektedir.
greybeard

0

Java'daki adımlar:

  1. Bir harita oluşturun.
  2. Listenin her iki dalında da geçiş yapmaya başlayın ve Düğümlerle ilgili bazı benzersiz şeyleri (düğüm kimliği diyelim) Anahtar olarak kullanarak listenin tüm çapraz düğümlerini Haritaya yerleştirin ve tümü için başlangıca Değerleri 1 koyun.
  3. İlk yinelenen anahtar geldiğinde, o Anahtar için değeri artırın (diyelim ki şimdi değeri> 1 olan 2 oldu.
  4. Değerin 1'den büyük olduğu ve iki listenin birleştiği düğüm olması gereken Anahtarı alın.

1
Ya birleştirilmiş kısımda döngü varsa?
Rohit

Ancak hata işleme döngüleri için bu, isyi'nin cevabına çok benziyor .
greybeard

0

"İsVisited" alanını tanıtarak bunu verimli bir şekilde çözebiliriz. İlk listeyi çaprazlayın ve sonuna kadar tüm düğümler için "isVisited" değerini "true" olarak ayarlayın. Şimdi ikinciden başlayın ve bayrağın doğru olduğu ilk düğümü bulun ve Boom, onun birleşme noktanız.


0

Adım 1: Her iki listenin uzunluğunu bulun Adım 2: Farkı bulun ve en büyük listeyi farkla taşıyın Adım 3: Şimdi her iki liste de benzer konumda olacaktır. Adım 4: Birleştirme noktasını bulmak için listeyi yineleyin

//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

(Her öğenin bir satıra daha iyi başladığı listeyi beğendim. Bir yazım denetleyicisi kullanmayı düşünün.)
greybeard

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;
}

Cevabınıza bir açıklama eklemeniz gerekiyor. Yalnızca kod yanıtları silinebilir.
rghome

0

Düğümün değerine karşı adreslerini saklamak için Harita veya Sözlük kullanın. Adres Harita / Sözlük'te zaten mevcutsa, anahtarın değeri cevaptır. Bunu ben yaptım:

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) karmaşıklık çözümü. Ama bir varsayıma dayanıyor.

varsayım şudur: her iki düğüm de yalnızca pozitif tam sayılara sahiptir.

mantık: list1'in tüm tam sayılarını negatif yapın. Daha sonra, negatif bir tam sayı elde edene kadar list2 üzerinden ilerleyin. Bulduktan sonra => al, işareti tekrar pozitif olarak değiştir ve geri dön.

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

İki işaretçi kullanabiliriz ve öyle bir şekilde hareket edebiliriz ki, işaretçilerden biri boş ise onu diğer listenin başına gösteririz ve diğeri için aynıysa, bu şekilde liste uzunlukları farklıysa ikinci geçişte buluşurlar. . List1'in uzunluğu n ve list2 m ise, farkları d = abs (nm) olur. Bu mesafeyi katedecekler ve birleşme noktasında buluşacaklar.
Kod:

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

Düğümlerini list1bir hashset'e ve döngüden ikinciye ekleyebilirsiniz ve kümede herhangi bir düğüm list2zaten varsa .Evet ise , bu birleştirme düğümüdür.

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 kullanarak çözüm

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

Bağlantılı listeyi düzenlemeye izin veriliyorsa,

  1. Ardından, liste 2'nin tüm düğümlerinin sonraki düğüm işaretleyicilerini boş olarak yapın.
  2. Listenin son düğümünün veri değerini bulun 1. Bu size "hi fi mantığı olmadan" her iki listenin tek geçişinde kesişen düğümü verecektir.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.