जांचें कि क्या दो लिंक की गई सूचियाँ आपस में मिलती हैं। यदि हां, तो कहां?


102

यह प्रश्न पुराना हो सकता है, लेकिन मैं एक उत्तर के बारे में नहीं सोच सकता।

कहते हैं, अलग-अलग लंबाई की दो सूची हैं, एक बिंदु पर विलय ; हमें कैसे पता चलेगा कि विलय बिंदु कहां है?

शर्तेँ:

  1. हम लंबाई नहीं जानते
  2. हमें प्रत्येक सूची को केवल एक बार पार्स करना चाहिए।

दो मर्ज किए गए लिंक का उदाहरण।


मर्ज का अर्थ है कि उस बिंदु से केवल एक सूची होगी।
10

क्या सूची में संशोधन की अनुमति है?
आर्टिलियस

1
मुझे पूरा यकीन है कि यह सूची में संशोधन के बिना काम नहीं करता है। (या सिर्फ इसे एक बार पार्स करने के लिए प्रतिबंध से बचने के लिए इसे कहीं और कॉपी करना।)
जॉर्ज शॉली

2
बात हो सकती है। लानत है साक्षात्कारकर्ताओं! हेहे
काइल रोज़ेंडो

1
मेरे पास एक दिलचस्प प्रस्ताव है ... सूची की आम पूंछ को मानते हुए असीम रूप से लंबा है। निरंतर मेमोरी का उपयोग करके आप नोड चौराहे को कैसे ढूंढ सकते हैं?
Akusete

जवाबों:


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
@ फॉरेथिंकर हैशिंग ने नोड्स का दौरा किया और / या उन्हें चिह्नित किया, जैसा कि देखा गया है कि उन्हें ओ (सूची लंबाई) मेमोरी की आवश्यकता है, जबकि कई समाधान (मेरा, हालांकि अपूर्ण और जटिल है) को ओ (1) मेमोरी की आवश्यकता होती है।
पी शेव्ड

156

निम्नलिखित अब तक का सबसे बड़ा मैंने देखा है - ओ (एन), कोई काउंटर नहीं। मैं विज़नपॉइंट पर एक उम्मीदवार एसएन को साक्षात्कार के दौरान मिला ।

इस तरह से एक इंटरस्टिंग पॉइंटर बनाएं: यह अंत तक हर बार आगे बढ़ता है, और फिर विपरीत सूची की शुरुआत में कूदता है, और इसी तरह। इनमें से दो को बनाएं, दो को इंगित करें। जब तक वे मिलते हैं, तब तक हर बार 1 से प्रत्येक बिंदु को आगे बढ़ाएं। यह एक या दो पास होने के बाद होगा।

मैं अभी भी साक्षात्कार में इस प्रश्न का उपयोग करता हूं - लेकिन यह देखने के लिए कि किसी को यह समझने में कितना समय लगता है कि यह समाधान क्यों काम करता है।


6
यह सिर्फ शानदार है!
कांग्रेस हुई

2
यह एक अच्छा जवाब है, लेकिन आपको दो बार सूचियों से गुजरना होगा जो स्थिति # 2 का उल्लंघन करती है।
14:05 बजे 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
प्रतिभाशाली। जो लोग समझ नहीं पाए, उनके लिए हेड 1-> टेल 1 -> हेड 2 -> चौराहे बिंदु और हेड 2 -> टेल 2-> हेड 1 -> चौराहे बिंदु से यात्रा की गई नोड्स की संख्या की गणना करें। दोनों समान होंगे (इसे सत्यापित करने के लिए अलग-अलग प्रकार की लिंक सूचीबद्ध करें)। कारण दोनों बिंदुओं को फिर से आईपी तक पहुंचने से पहले एक ही दूरी के हेड 1-> आईपी + हेड 2-> आईपी से यात्रा करना है। इसलिए जब तक यह आईपी तक पहुंचता है, तब तक दोनों बिंदु समान होंगे और हमारे पास विलय बिंदु होगा।
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
आज, जब हम वोदका पी रहे थे, तो मैंने इस प्रश्न को अपने एक दोस्त को प्रस्तावित किया, और उसने तुम्हारा वही जवाब दिया और इसे एसओ पर पोस्ट करने के लिए कहा। लेकिन आप पहले लगते हैं। इसलिए मैं आपसे मेरे लिए एक +1 बनाऊंगा और मेरी इच्छा है कि मैं एक और +1 करूं।
21:39 पर पी शेव्ड

2
+1 इस तरह से और सूची में किसी भी संशोधन की आवश्यकता नहीं है, आमतौर पर लिंक-सूची के अधिकांश कार्यान्वयन आमतौर पर लंबाई के लिए प्रदान करते हैं
keshav84

3
हमारे पास बहुत से पावेल हैं। मेरे समाधान के लिए सूची को संशोधित करने की आवश्यकता नहीं है।
पावल रेड्ज़विलोव्स्की

अच्छा उत्तर। हालांकि इसके लिए समय की जटिलता क्या होगी। 0 (n + m)? कहाँ n = सूची 1 में नोड्स, सूची 2 में मीटर = नोड्स?
विहान वर्मा

दोनों सूचियों में दोनों बिंदुओं को स्थानांतरित करने के बजाय: हम बस यह देख सकते हैं कि क्या अंतर> = दो मार्ग के छोटे हैं, यदि हाँ, तो छोटी सूची में छोटी सी चाल से अलग करें और छोटी सूची में अलग + 1 मान से आगे बढ़ें; यदि अंतर 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
काइल रोज़ेन्डो

@ केइल रोज़न्डो, ठीक है, मेरे समाधान में परिवर्तन होता है जिस तरह से वे प्रसंस्करण के बाद बहाल किए जा सकते हैं। लेकिन यह अवधारणा का अधिक स्पष्ट प्रदर्शन है
P Shved

मैंने यह नहीं देखा कि सूची में संशोधन की अनुमति नहीं थी। मैं इसे एक विचार दूंगा, लेकिन देखा गया हर नोड संग्रहीत किए बिना कुछ भी दिमाग में नहीं आ रहा है।
tster

10
चलो, यह सही जवाब है! हमें बस प्रश्न को समायोजित करने की आवश्यकता है :)
P Shiv

23
मेमोरी लीक बनाने के लिए उत्कृष्ट एल्गोरिथ्म।
कारोली होर्वाथ

14

अगर हम सूची को दो बार ठीक कर सकते हैं, तो मैं मर्ज बिंदु निर्धारित करने के लिए विधि प्रदान कर सकता हूं:

  • दोनों सूचियों को पुनरावृत्त करें और ए और बी की लंबाई की गणना करें
  • लंबाई के अंतर की गणना C = | AB |
  • दोनों सूची को एक साथ पुनरावृत्त करना शुरू करें, लेकिन सूची में अतिरिक्त सी चरण बनाएं जो अधिक था
  • यह दो बिंदु विलय बिंदु में एक दूसरे से मिलेंगे

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
यह सूची को दो बार संसाधित करने के बराबर है।
जॉर्ज स्कोली

मुझे लगता है कि, तकनीकी रूप से, आप दो बार सूचियों के साथ सामान कर रहे हैं, लेकिन यह काइल रोजेंडो के समाधान पर एक महत्वपूर्ण सुधार है। अब, यदि, सूची को संसाधित करना ’को following लिंक मूल्य को पढ़ने और पॉइंटर के बाद’ के रूप में परिभाषित किया गया है, तो यह तर्क दिया जा सकता है कि यह सूची को एक बार संसाधित करता है - यह प्रत्येक लिंक मूल्य को एक बार पढ़ता है, इसे संग्रहीत करता है और फिर उनकी तुलना करता है।
स्किज़ ऑक्ट

निश्चित रूप से मेरा तेजी से होने जा रहा है, इसमें कोई संदेह नहीं है।
काइल रोज़ेंडो

7

आप नोड्स के एक सेट का उपयोग कर सकते हैं। एक सूची के माध्यम से Iterate करें और सेट में प्रत्येक नोड जोड़ें। फिर दूसरी सूची के माध्यम से पुनरावृत्ति और प्रत्येक पुनरावृत्ति के लिए, जांचें कि क्या नोड सेट में मौजूद है। यदि ऐसा होता है, तो आपको अपना मर्ज बिंदु मिल गया है :)


मुझे डर है (Ω (n) अतिरिक्त स्थान के कारण) यह एकमात्र तरीका है (सूची के पुनर्निर्माण का प्रकार नहीं है) और सूची को एक से अधिक बार पार्स नहीं करना। सूची में एक लूप का पता लगाना पहली सूची के लिए तुच्छ है (अगर सेट में नोड की जाँच करें) - समाप्ति सुनिश्चित करने के लिए दूसरी सूची पर किसी भी लूप डिटेक्शन विधि का उपयोग करें। (साक्षात्कार का प्रश्न किसी समस्या के बयान को ध्यान से सुनने के बारे में हो सकता है , और एक हथौड़ा का उपयोग करने के लिए कूदना नहीं है जो आपको पता है कि एक कील पर कुछ हिट करने के लिए पता नहीं है।)
ग्रेबर्ड

6

यह यकीनन "प्रत्येक सूची को केवल एक बार पार्स" का उल्लंघन करता है, लेकिन कछुआ और हरे एल्गोरिथ्म (एक चक्रीय सूची के मर्ज बिंदु और चक्र की लंबाई का पता लगाने के लिए) को लागू करें ताकि आप सूची ए पर शुरू करें, और जब आप NULL पर पहुंचें अंत में आप दिखावा करते हैं कि यह सूची B की शुरुआत का एक संकेतक है, इस प्रकार यह चक्रीय सूची का रूप बनाता है। एल्गोरिथ्म तब आपको बताएगा कि विकिपीडिया विवरण के अनुसार सूची A मर्ज कितनी दूर है (चर 'म्यू')।

इसके अलावा, "लैम्ब्डा" मूल्य आपको सूची बी की लंबाई बताता है, और यदि आप चाहते हैं, तो आप एल्गोरिथ्म के दौरान सूची की लंबाई बाहर काम कर सकते हैं (जब आप NULL लिंक को पुनर्निर्देशित करते हैं)।


बहुत कुछ जो मैंने कहा, सिर्फ कट्टर नामों से। : पी
काइल रोसेन्डो

हर्गिज नहीं। यह समाधान ओ (एन) संचालन में है और ओ (1) मेमोरी उपयोग में (वास्तव में केवल दो पॉइंटर चर की आवश्यकता है)।
आर्टिलियस

हाँ, मेरी पूर्व टिप्पणी को हटा देना चाहिए क्योंकि मेरा समाधान थोड़ा बदल गया। हेहे।
काइल रोसेन्डो

लेकिन मैं यह नहीं देखता कि यह कैसे लागू हुआ?
आर्टिलियस

आपकी व्याख्या ने किया, न कि एल्गोरिथम ने। शायद मैं इसे अलग तरह से देखता हूं, लेकिन हे।
काइल रोज़ेंडो

3

हो सकता है कि मैं इसे सरल कर रहा हूं, लेकिन बस छोटी से छोटी सूची को पुनरावृत्त करना और Linkविलय के बिंदु के रूप में अंतिम नोड्स का उपयोग करना है ?

तो, Data->Link->Link == NULLअंत बिंदु कहाँ है, Data->Linkविलय बिंदु (सूची के अंत में) के रूप में दे रहा है ।

संपादित करें:

ठीक है, आपके द्वारा पोस्ट की गई तस्वीर से, आप दो सूचियों को पार्स करते हैं, सबसे छोटा। सबसे छोटी सूची के साथ आप निम्नलिखित नोड के संदर्भों को बनाए रख सकते हैं। अब, जब आप दूसरी सूची को पार्स करते हैं, तो आप संदर्भ पर एक तुलना करते हैं, जहां संदर्भ [i] लिंक्डलिस्ट [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

नोट मिटाया मैंने नोड संरचना को संरेखित किया था, इसलिए जब मॉलॉक () एक नोड, पते को डब्ल्यू / 16 बाइट्स से जोड़ा जाता है, तो कम से कम 4 बिट्स देखें। सबसे कम बिट्स 0s, यानी 0x0 या 000b हैं। इसलिए यदि आपके समान विशेष मामले (नोड पता संरेखित) में हैं, तो आप इन कम से कम 4 बिट्स का उपयोग कर सकते हैं। उदाहरण के लिए जब दोनों सूचियों को सिर से पूंछ तक यात्रा करते हैं, तो विजिटिंग नोड पते के 4 बिट्स में से 1 या 2 सेट करें, अर्थात, एक ध्वज सेट करें;

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

ऊपर दिए गए झंडे वास्तविक नोट पते को प्रभावित नहीं करेंगे, लेकिन केवल आपके SAVED नोड पॉइंटर मान को प्रभावित करेंगे।

एक बार पाया गया कि किसी ने ध्वज को सेट किया है, तो पहले पाया गया नोड मर्ज बिंदु होना चाहिए। किए जाने के बाद, आप अपने द्वारा सेट किए गए ध्वज बिट्स को साफ़ करके नोड पते को पुनर्स्थापित करेंगे। जबकि एक महत्वपूर्ण बात यह है कि जब आपको स्वच्छ करने के लिए iterate (जैसे नोड = नोड-> अगला) सावधान रहना चाहिए। याद रखें कि आपने ध्वज बिट्स सेट किया था, इसलिए इस तरह से करें

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

क्योंकि यह प्रस्ताव संशोधित नोड पते को बहाल करेगा, इसे "कोई संशोधन नहीं" माना जा सकता है।


+1, यह वही है जो स्वाभाविक रूप से "इटर्सेट केवल एक बार" के साथ दिमाग में आता है कि यह वोट क्यों नहीं मिला! सुंदर समाधान।
जामन

3

एक सरल समाधान हो सकता है लेकिन एक सहायक स्थान की आवश्यकता होगी। विचार एक सूची को पार करने और प्रत्येक पते को हैश मानचित्र में संग्रहीत करने के लिए है, अब दूसरी सूची को पार कर सकता है और पता हैश के मानचित्र में निहित है या नहीं। प्रत्येक सूची का केवल एक बार पता लगाया जाता है। किसी भी सूची में कोई संशोधन नहीं है। लंबाई अभी भी अज्ञात है। सहायक स्थान का उपयोग किया जाता है: O (n) जहां 'n' पहली सूची के लिए लंबा है।


2

यह समाधान प्रत्येक सूची को केवल एक बार पुन: प्रसारित करता है ... सूची का कोई संशोधन भी आवश्यक नहीं है..हालांकि आप अंतरिक्ष के बारे में शिकायत कर सकते हैं ..
1) मूल रूप से आप सूची 1 में पुनरावृति करते हैं और प्रत्येक नोड के पते को एक सरणी में संग्रहीत करते हैं (जो अहस्ताक्षरित अंतर मान संग्रहीत करता है)
2) फिर आप सूची 2 को पुनरावृत्त करते हैं, और प्रत्येक नोड के पते के लिए ---> आप उस सरणी के माध्यम से खोजते हैं जिसे आप मैच पाते हैं या नहीं ... यदि आप करते हैं तो यह विलय नोड है

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

आशा है कि यह एक वैध समाधान है ...


यह बहुत अधिक सूची में से एक को एक से अधिक बार पुनरावृत्त करता है, हालांकि सूची के बजाय एक सरणी के रूप में।
13

1

किसी भी सूची को संशोधित करने की आवश्यकता नहीं है। एक समाधान है जिसमें हमें केवल प्रत्येक सूची को एक बार पार करना होगा।

  1. दो स्टैक बनाएं, स्टेक 1 और स्टेक 2 को कहने दें।
  2. 1 लिस्ट को ट्रावर्स करें और स्टेक 1 में आपके द्वारा खोले गए प्रत्येक नोड की एक प्रति को धक्का दें।
  3. चरण दो के रूप में भी लेकिन इस बार 2 सूची में आगे बढ़े और स्टेक 2 में नोड्स की प्रतिलिपि को आगे बढ़ाएं।
  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;
}


0

यहाँ भोली समाधान है, पूरी सूची को पार करने के लिए कोई नेड नहीं है।

यदि आपके संरचित नोड में तीन फ़ील्ड हैं जैसे

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

आप दो सूचियों के प्रमुख की ओर इशारा करते हुए दो सिर (हेड 1 और हेड 2) हैं।

दोनों सूची को समान गति से आगे बढ़ाएं और उस नोड के लिए झंडा = 1 (देखा गया झंडा) लगाएं,

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

0

इस बारे में कैसा है:

  1. यदि आपको केवल प्रत्येक सूची को केवल एक बार ही पार करने की अनुमति है, तो आप एक नया नोड बना सकते हैं, इस नए नोड के लिए प्रत्येक नोड बिंदु के लिए पहली सूची को पार कर सकते हैं, और दूसरी सूची को देखने के लिए कि क्या कोई नोड आपके नए नोड की ओर इशारा कर रहा है ( वह आपका मर्ज बिंदु है)। यदि दूसरा ट्रैवर्सल आपके नए नोड तक नहीं जाता है, तो मूल सूचियों में मर्ज बिंदु नहीं होता है।

  2. यदि आपको सूचियों को एक से अधिक बार पार करने की अनुमति है, तो आप हमारी सूची खोजने के लिए प्रत्येक सूची को पार कर सकते हैं और यदि वे अलग हैं, तो लंबी सूची की शुरुआत में "अतिरिक्त" नोड को छोड़ दें। फिर बस एक समय में दोनों चरणों को सूचीबद्ध करता है और पहले विलय नोड का पता लगाता है।


1. न केवल संशोधित करता है बल्कि पहली सूची को नष्ट कर देता है। 2. बार-बार सुझाव दिया जाता है।
greybeard

0

जावा में कदम:

  1. एक नक्शा बनाएँ।
  2. सूची की दोनों शाखाओं में ट्रैवर्सिंग शुरू करें और नोड्स (नोड नोड) से संबंधित कुछ अनोखी चीज़ का उपयोग करके मानचित्र में सूची के सभी ट्रैवर्स किए गए नोड्स को कुंजी के रूप में डालें और सभी के लिए प्रारंभ में मान 1 के रूप में डालें।
  3. जब कभी पहली डुप्लिकेट कुंजी आती है, तो उस कुंजी का मान बढ़ाएँ (मान लें कि अब इसका मान 2 हो गया जो कि> 1 है।
  4. कुंजी प्राप्त करें जहां मान 1 से अधिक है और वह नोड होना चाहिए जहां दो सूचियां विलय कर रही हैं।

1
क्या होगा यदि हमारे पास मर्ज किए गए भाग में चक्र है?
रोहित

लेकिन साइकिल को संभालने में त्रुटि के लिए, यह बहुत ही इस्की उत्तर की तरह दिखता है ।
ग्रेबियर्ड

0

हम कुशलता से इसे "प्रतिष्ठित" क्षेत्र को पेश करके हल कर सकते हैं। अंत तक सभी नोड्स के लिए पहली सूची और सेट "निर्धारित" मान "ट्रू" है। अब दूसरे से शुरू करें और पहले नोड को ढूंढें जहां झंडा सच है और बूम, इसका विलय बिंदु।


0

चरण 1: दोनों सूची का पाला पड़ना चरण 2: अंतर का पता लगाएं और सबसे बड़ी सूची को अंतर के साथ स्थानांतरित करें चरण 3: अब दोनों सूची समान स्थिति में होगी। चरण 4: मर्ज बिंदु खोजने के लिए सूची के माध्यम से Iterate करें

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

आपको अपने उत्तर में कुछ स्पष्टीकरण जोड़ने की आवश्यकता है। कोड केवल उत्तर हटाए जा सकते हैं।
रगोम

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) जटिलता समाधान। लेकिन एक धारणा पर आधारित है।

धारणा है: दोनों नोड्स केवल सकारात्मक पूर्णांक हैं।

तर्क: सूची 1 के सभी पूर्णांक को ऋणात्मक बनाएं। फिर सूची 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

जावास्क्रिप्ट का उपयोग कर समाधान

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. सूची के अंतिम नोड का डेटा मूल्य ज्ञात करें। यह आपको दोनों सूचियों के एकल ट्रैवर्सल में "नो हाई फाई लॉजिक" के साथ इंटरसेक्टिंग नोड देगा।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.