Kiểm tra xem hai danh sách được liên kết có hợp nhất không. Nếu vậy, ở đâu?


102

Câu hỏi này có thể cũ, nhưng tôi không thể nghĩ ra câu trả lời.

Giả sử, có hai danh sách có độ dài khác nhau, hợp nhất tại một điểm ; làm cách nào để biết điểm hợp nhất ở đâu?

Điều kiện:

  1. Chúng tôi không biết chiều dài
  2. Chúng ta chỉ nên phân tích cú pháp mỗi danh sách một lần.

Ví dụ về hai danh sách liên kết đã hợp nhất.


hợp nhất có nghĩa là từ thời điểm đó sẽ chỉ có một danh sách.
rplusg

có được phép sửa đổi danh sách không?
Artelius

1
Tôi khá chắc chắn rằng nó không hoạt động nếu không có sửa đổi danh sách. (Hoặc chỉ cần sao chép nó ở một nơi khác để tránh những hạn chế để phân tích nó một lần duy nhất.)
Georg Schölly

2
Có thể đã là điểm. Bọn phỏng vấn chết tiệt! Hehe
Kyle Rosendo

1
Tôi có một đề xuất thú vị ... giả sử phần đuôi chung của danh sách dài vô hạn. Làm thế nào bạn có thể tìm thấy giao điểm nút bằng cách sử dụng bộ nhớ không đổi?
Akusete

Câu trả lời:


36

Nếu

  • bởi "không được phép sửa đổi" có nghĩa là "bạn có thể thay đổi nhưng cuối cùng chúng sẽ được khôi phục", và
  • chúng tôi có thể lặp lại danh sách chính xác hai lần

thuật toán sau đây sẽ là giải pháp.

Đầu tiên, những con số. Giả sử danh sách đầu tiên có độ dài a+cvà danh sách thứ hai có độ dài b+c, trong đó cđộ dài của "đuôi" chung của chúng (sau điểm hợp nhất). Hãy biểu thị chúng như sau:

x = a+c
y = b+c

Vì chúng ta không biết độ dài, chúng ta sẽ tính toán xykhông cần lặp lại; bạn sẽ thấy như thế nào.

Sau đó, chúng tôi lặp lại từng danh sách và đảo ngược chúng trong khi lặp lại! Nếu cả hai trình vòng lặp đạt đến điểm hợp nhất cùng một lúc, thì chúng tôi sẽ tìm ra nó bằng cách so sánh đơn thuần. Nếu không, một con trỏ sẽ đạt đến điểm hợp nhất trước con trỏ kia.

Sau đó, khi trình lặp khác đạt đến điểm hợp nhất, nó sẽ không tiếp tục đến đuôi chung. Thay vào đó, sẽ quay lại phần đầu cũ của danh sách đã đạt đến điểm hợp nhất trước đó! Vì vậy, trước khi nó đến cuối danh sách đã thay đổi (tức là đầu cũ của danh sách khác), anh ta sẽ thực hiện a+b+1tổng số lần lặp lại. Hãy gọi nó z+1.

Con trỏ đạt đến điểm hợp nhất trước tiên, sẽ tiếp tục lặp lại, cho đến khi đến cuối danh sách. Số lần lặp lại nó phải được tính toán và bằng x.

Sau đó, con trỏ này lặp lại và đảo ngược danh sách một lần nữa. Nhưng bây giờ nó sẽ không quay trở lại đầu danh sách mà nó bắt đầu ban đầu! Thay vào đó, nó sẽ đi đến đầu danh sách khác! Số lần lặp nó đã thực hiện phải được tính toán và bằng y.

Vì vậy, chúng tôi biết những con số sau:

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

Từ đó chúng tôi xác định rằng

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

Mà giải quyết vấn đề.


2
Bình luận cho các trạng thái câu hỏi sửa đổi danh sách không được phép!
Skizz

1
Tôi thích câu trả lời này (rất sáng tạo). Vấn đề duy nhất tôi gặp phải là nó giả định rằng bạn biết độ dài của cả hai danh sách.
tster

bạn không thể sửa đổi danh sách và chúng tôi không biết độ dài - đây là những ràng buộc ... bất kỳ cách nào, cảm ơn vì một câu trả lời sáng tạo.
rplusg

2
@tster, @calvin, câu trả lời không giả sử, chúng tôi cần độ dài. Nó có thể được tính toán nội tuyến. Thêm giải thích cho câu trả lời của tôi.
P Shved

2
@Forethinker băm các nút đã truy cập và / hoặc đánh dấu chúng như đã thấy yêu cầu bộ nhớ O (độ dài danh sách), trong khi nhiều giải pháp (bao gồm cả giải pháp của tôi, tuy nhiên không hoàn hảo và phức tạp) yêu cầu bộ nhớ O (1).
P Shved

156

Điều sau là tuyệt vời nhất trong tất cả những gì tôi từng thấy - O (N), không có quầy. Tôi đã nhận được nó trong một cuộc phỏng vấn với một ứng viên SN tại VisionMap .

Tạo một con trỏ tương tác như thế này: nó tiến về phía trước mọi lúc cho đến khi kết thúc, sau đó chuyển sang đầu danh sách ngược lại, v.v. Tạo hai trong số này, trỏ đến hai đầu. Tiến từng con trỏ lên 1 lần cho đến khi chúng gặp nhau. Điều này sẽ xảy ra sau một hoặc hai lượt.

Tôi vẫn sử dụng câu hỏi này trong các cuộc phỏng vấn - nhưng để xem ai đó mất bao lâu để hiểu tại sao giải pháp này hoạt động.


6
thật là tuyệt vời!
Cong Hui

2
Đây là một câu trả lời hay, nhưng bạn phải xem qua hai lần danh sách vi phạm điều kiện số 2.
tster

2
Tôi thấy giải pháp này khá thanh lịch, nếu một điểm hợp nhất được đảm bảo có mặt. Nó sẽ không hoạt động để phát hiện các điểm hợp nhất, vì nếu một điểm không có mặt, nó sẽ lặp lại vô hạn.
hướng luân phiên

4
Thật là tuyệt vời! Giải thích: chúng ta có 2 danh sách: a-b-c-x-y-zp-q-x-y-z. đường dẫn của con trỏ đầu tiên a,b,c,x,y,z,p,q,x, đường dẫn của con trỏ thứ haip,q,x,y,z,a,b,c,x
Nikolai Golub

14
Xuất sắc. Đối với những người không hiểu, hãy đếm số nút đi từ head1-> tail1 -> head2 -> giao điểm và head2 -> tail2-> head1 -> giao điểm. Cả hai sẽ bằng nhau (Vẽ các loại danh sách liên kết khác nhau để xác minh điều này). Lý do là cả hai con trỏ phải di chuyển cùng một khoảng cách head1-> IP + head2-> IP trước khi đạt lại IP. Vì vậy, vào thời điểm nó đạt đến IP, cả hai con trỏ sẽ bằng nhau và chúng ta có điểm hợp nhất.
adev

91

Câu trả lời của Pavel yêu cầu sửa đổi danh sách cũng như lặp lại mỗi danh sách hai lần.

Đây là một giải pháp chỉ yêu cầu lặp lại mỗi danh sách hai lần (lần đầu tiên để tính độ dài của chúng; nếu độ dài được cung cấp, bạn chỉ cần lặp lại một lần).

Ý tưởng là bỏ qua các mục bắt đầu của danh sách dài hơn (không thể có điểm hợp nhất ở đó), để hai con trỏ cách cuối danh sách một khoảng bằng nhau. Sau đó, di chuyển chúng về phía trước cho đến khi chúng hợp nhất.

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

Đây là tiệm cận giống (thời gian tuyến tính) với câu trả lời khác của tôi nhưng có lẽ có hằng số nhỏ hơn, vì vậy có lẽ nhanh hơn. Nhưng tôi nghĩ câu trả lời khác của tôi hay hơn.


4
Hôm nay, khi chúng tôi đang uống vodka, tôi đã đề xuất câu hỏi này với một người bạn của tôi, và anh ấy đã đưa ra câu trả lời giống như của bạn và yêu cầu đăng nó lên SO. Nhưng bạn dường như là người đầu tiên. Vì vậy, tôi sẽ +1 cho bạn từ tôi và tôi ước tôi có thể thực hiện +1 khác.
P Shved

2
1 như thế này và cũng doesnt cần bất kỳ sửa đổi vào danh sách, cũng hầu hết các triển khai danh sách liên kết thường cung cấp cho chiều dài
keshav84

3
Chúng ta có quá nhiều Pavel. Giải pháp của tôi không yêu cầu sửa đổi danh sách.
Pavel Radzivilovsky

Câu trả lời tốt. Tuy nhiên, thời gian sẽ phức tạp cho việc này. 0 (n + m)? trong đó n = nút trong danh sách 1, m = nút trong danh sách 2?
Vihaan Verma

thay vì di chuyển cả hai con trỏ trong cả hai danh sách: chúng ta chỉ có thể xem nếu diff> = small của hai đường dẫn, nếu có, sau đó di chuyển trong danh sách nhỏ bằng giá trị nhỏ khác di chuyển trong danh sách nhỏ bằng giá trị khác + 1; nếu diff bằng 0 thì nút cuối cùng là câu trả lời.
Vishal Anand

30

Chà, nếu bạn biết rằng chúng sẽ hợp nhất:

Giả sử bạn bắt đầu với:

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

1) Đi qua danh sách đầu tiên đặt mỗi con trỏ tiếp theo thành NULL.

Bây giờ bạn có:

A   B   C

1-->2-->3   4   5

2) Bây giờ đi qua danh sách thứ hai và đợi cho đến khi bạn thấy NULL, đó là điểm hợp nhất của bạn.

Nếu bạn không thể chắc chắn rằng chúng hợp nhất, bạn có thể sử dụng giá trị sentinel cho giá trị con trỏ, nhưng điều đó không thanh lịch.


3
Tuy nhiên, bạn phá hủy danh sách trong quá trình này, không bao giờ được sử dụng một lần nữa: P
Kyle Rosendo

@Kyle Rozendo, tốt, giải pháp của tôi thay đổi danh sách theo cách chúng có thể được khôi phục sau khi xử lý. Nhưng đây là minh chứng rõ ràng hơn về khái niệm
P Shved

Tôi không thấy rằng việc sửa đổi danh sách không được phép. Tôi sẽ suy nghĩ lại, nhưng sẽ chẳng có gì đáng suy nghĩ nếu không lưu trữ mọi nút được nhìn thấy.
tster

10
Thôi nào, đó là câu trả lời chính xác! Chúng tôi chỉ cần điều chỉnh câu hỏi :)
P Shved

23
Thuật toán tuyệt vời để tạo rò rỉ bộ nhớ.
Karoly Horvath

14

Nếu chúng tôi có thể lặp lại danh sách chính xác hai lần, thì tôi có thể cung cấp phương pháp xác định điểm hợp nhất:

  • lặp lại cả hai danh sách và tính độ dài A và B
  • tính hiệu độ dài C = | AB |;
  • bắt đầu lặp lại cả hai danh sách đồng thời, nhưng thực hiện các bước C bổ sung trên danh sách lớn hơn
  • hai con trỏ này sẽ gặp nhau ở điểm hợp nhất

8

Đây là một giải pháp, tính toán nhanh chóng (lặp lại mỗi danh sách một lần) nhưng sử dụng nhiều bộ nhớ:

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
Điều đó tương đương với việc xử lý một danh sách hai lần.
Georg Schölly

Tôi cho rằng về mặt kỹ thuật, bạn đang làm việc với danh sách hai lần, nhưng đó là một cải tiến đáng kể trong giải pháp của Kyle Rozendo. Bây giờ, nếu 'xử lý danh sách' được định nghĩa là 'đọc giá trị liên kết và theo dõi con trỏ' thì có thể lập luận rằng nó xử lý danh sách một lần - nó đọc từng giá trị liên kết một lần, lưu trữ và sau đó so sánh chúng.
Skizz

Chắc chắn là sẽ nhanh hơn của tôi, không nghi ngờ gì nữa.
Kyle Rosendo

7

Bạn có thể sử dụng một tập hợp các Nút. Lặp lại một danh sách và thêm từng Node vào tập hợp. Sau đó, lặp qua danh sách thứ hai và đối với mỗi lần lặp, hãy kiểm tra xem Node có tồn tại trong tập hợp hay không. Nếu đúng, bạn đã tìm thấy điểm hợp nhất của mình :)


Tôi e rằng (vì Ω (n) không gian bổ sung) đây là cách tiếp cận duy nhất (không phải là loại xây dựng lại (các) danh sách và) không phân tích cú pháp một danh sách nhiều lần. Việc phát hiện một vòng lặp trong danh sách là không đáng kể đối với danh sách đầu tiên (kiểm tra xem nút có trong tập hợp hay không) - sử dụng bất kỳ phương pháp phát hiện vòng lặp nào trong danh sách thứ hai để đảm bảo kết thúc. (Các câu hỏi phỏng vấn có thể đã về nghe một cách cẩn thận để một tuyên bố vấn đề, và không nhảy vào để sử dụng một cái búa bạn tình cờ biết đến không phải cái gì hit khá một móng tay.)
lọ

6

Điều này được cho là vi phạm điều kiện "phân tích cú pháp mỗi danh sách chỉ một lần", nhưng triển khai thuật toán rùa và thỏ (được sử dụng để tìm điểm hợp nhất và độ dài chu kỳ của danh sách tuần hoàn) để bạn bắt đầu ở Danh sách A và khi bạn đạt đến NULL tại kết thúc bạn giả vờ đó là một con trỏ đến đầu danh sách B, do đó tạo ra sự xuất hiện của danh sách tuần hoàn. Sau đó, thuật toán sẽ cho bạn biết chính xác Danh sách A được hợp nhất bao xa (biến 'mu' theo mô tả của Wikipedia).

Ngoài ra, giá trị "lambda" cho bạn biết độ dài của danh sách B và nếu bạn muốn, bạn có thể tính độ dài của danh sách A trong thuật toán (khi bạn chuyển hướng liên kết NULL).


Khá nhiều những gì tôi đã nói, chỉ với những cái tên huyền ảo hơn. : P
Kyle Rosendo

Không có gì. Giải pháp này là O (n) trong các phép toán và O (1) trong việc sử dụng bộ nhớ (thực tế chỉ yêu cầu hai biến con trỏ).
Artelius

Đúng, lẽ ra phải xóa bình luận trước của tôi vì giải pháp của tôi đã thay đổi một chút. Hehe.
Kyle Rosendo

Nhưng tôi không thấy điều đó đã được áp dụng ngay từ đầu như thế nào?
Artelius

Giải thích của bạn đã làm, không phải chính thuật toán. Có lẽ tôi nhìn nhận nó theo cách khác, nhưng hey.
Kyle Rosendo

3

Có lẽ tôi đã quá đơn giản hóa điều này, nhưng chỉ cần lặp lại danh sách nhỏ nhất và sử dụng các nút cuối cùng Linklàm điểm hợp nhất?

Vì vậy, đâu Data->Link->Link == NULLlà điểm kết thúc, cho Data->Linklà điểm hợp nhất (ở cuối danh sách).

BIÊN TẬP:

Được rồi, từ hình ảnh bạn đã đăng, bạn phân tích cú pháp hai danh sách, danh sách nhỏ nhất đầu tiên. Với danh sách nhỏ nhất, bạn có thể duy trì các tham chiếu đến nút sau. Bây giờ, khi bạn phân tích cú pháp danh sách thứ hai, bạn thực hiện so sánh trên tham chiếu để tìm nơi Tham chiếu [i] là tham chiếu tại LinkedList [i] -> Liên kết. Điều này sẽ cho điểm hợp nhất. Thời gian để giải thích bằng hình ảnh (chồng các giá trị trên hình lên OP).

Bạn có một danh sách được liên kết (các tham chiếu được hiển thị bên dưới):

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

Bạn có một danh sách được liên kết thứ hai:

1->2->

Với danh sách đã hợp nhất, các tham chiếu sau đó sẽ đi như sau:

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

Do đó, bạn lập bản đồ danh sách "nhỏ hơn" đầu tiên (vì danh sách đã hợp nhất, danh sách mà chúng tôi đang đếm có độ dài là 4 và danh sách chính là 5)

Lặp qua danh sách đầu tiên, duy trì một tham chiếu các tài liệu tham khảo.

Danh sách sẽ bao gồm các tài liệu tham khảo sau Pointers { 1, 2, D, E }.

Bây giờ chúng ta đi qua danh sách thứ hai:

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

Chắc chắn, bạn duy trì một danh sách con trỏ mới, nhưng điều đó không nằm ngoài thông số kỹ thuật. Tuy nhiên, danh sách đầu tiên được phân tích cú pháp chính xác một lần và danh sách thứ hai sẽ chỉ được phân tích cú pháp hoàn toàn nếu không có điểm hợp nhất. Nếu không, nó sẽ kết thúc sớm hơn (tại điểm hợp nhất).


Cũng có một chút thay đổi so với những gì tôi muốn nói lúc đầu, nhưng từ những gì OP dường như muốn, điều này sẽ làm được điều đó.
Kyle Rosendo

Bây giờ nó rõ ràng hơn. Nhưng tuyến tính trong sử dụng bộ nhớ. Tôi không thích điều đó.
Artelius

Câu hỏi không yêu cầu nhiều hơn, nếu không toàn bộ quá trình có thể được đa luồng. Đây vẫn là một chế độ xem "cấp cao nhất" đơn giản của giải pháp, mã có thể được thực hiện theo bất kỳ cách nào. :)
Kyle Rosendo

1
Uh, cái gì? Đa luồng là một cách tận dụng tốt hơn sức mạnh xử lý, không làm giảm tổng sức mạnh xử lý mà một thuật toán yêu cầu. Và nói rằng mã có thể được triển khai theo bất kỳ cách nào chỉ là một cái cớ.
Artelius

1
Điều này thực sự làm cong 'phân tích cú pháp mỗi danh sách chỉ một lần' đến gần điểm phá vỡ. Tất cả những gì bạn đang làm là sao chép một danh sách và sau đó kiểm tra danh sách kia với bản sao.
Skizz

3

Tôi đã thử nghiệm trường hợp hợp nhất trên FC9 x86_64 của mình và in mọi địa chỉ nút như được hiển thị bên dưới:

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


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

Lưu ý rằng tôi đã căn chỉnh cấu trúc nút, vì vậy khi malloc () một nút, địa chỉ được căn chỉnh w / 16 byte, hãy xem ít nhất 4 bit. Các bit ít nhất là 0s, tức là 0x0 hoặc 000b. Vì vậy, nếu bạn cũng ở trong cùng một trường hợp đặc biệt (địa chỉ nút được căn chỉnh), bạn có thể sử dụng ít nhất 4 bit này. Ví dụ: khi di chuyển cả hai danh sách từ đầu đến đuôi, hãy đặt 1 hoặc 2 trong số 4 bit của địa chỉ nút truy cập, nghĩa là đặt cờ;

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

Lưu ý rằng các cờ ở trên sẽ không ảnh hưởng đến địa chỉ nút thực mà chỉ ảnh hưởng đến giá trị con trỏ nút SAVED của bạn.

Sau khi tìm thấy ai đó đã đặt (các) bit cờ, thì nút được tìm thấy đầu tiên phải là điểm hợp nhất. sau khi hoàn tất, bạn sẽ khôi phục địa chỉ nút bằng cách xóa các bit cờ mà bạn đã đặt. trong khi một điều quan trọng là bạn nên cẩn thận khi lặp lại (ví dụ: nút = nút-> tiếp theo) để làm sạch. hãy nhớ rằng bạn đã đặt các bit cờ, vì vậy hãy làm theo cách này

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

Vì đề xuất này sẽ khôi phục các địa chỉ nút đã sửa đổi, nên nó có thể được coi là "không sửa đổi".


+1, đây là điều tự nhiên xuất hiện trong đầu với "chỉ lặp lại một lần" dunno tại sao điều này không bao giờ được bình chọn! Giải pháp đẹp.
jman

3

Có thể có một giải pháp đơn giản nhưng sẽ yêu cầu không gian hỗ trợ. Ý tưởng là duyệt qua một danh sách và lưu trữ từng địa chỉ trong một bản đồ băm, bây giờ hãy xem qua danh sách kia và khớp xem địa chỉ đó có nằm trong bản đồ băm hay không. Mỗi danh sách chỉ được duyệt một lần. Không có sửa đổi đối với bất kỳ danh sách nào. Chiều dài vẫn chưa rõ. Không gian bổ trợ được sử dụng: O (n) trong đó 'n' là độ dài của danh sách đầu tiên được duyệt qua.


2

giải pháp này chỉ lặp lại mỗi danh sách một lần ... không cần sửa đổi danh sách nữa..mặc dù bạn có thể phàn nàn về dung lượng ..
1) Về cơ bản, bạn lặp lại trong list1 và lưu trữ địa chỉ của mỗi nút trong một mảng (lưu trữ giá trị int không dấu)
2) Sau đó, bạn lặp lại list2, và đối với địa chỉ của mỗi nút ---> bạn tìm kiếm trong mảng mà bạn tìm thấy khớp hay không ... nếu bạn làm vậy thì đây là nút hợp nhất

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

Hy vọng nó là một giải pháp hợp lệ ...


Điều này khá nhiều lần lặp lại một trong các danh sách, mặc dù ở dạng một mảng thay vì chính danh sách.
syockit

1

Không cần phải sửa đổi bất kỳ danh sách nào. Có một giải pháp mà chúng ta chỉ phải duyệt qua từng danh sách một lần.

  1. Tạo hai ngăn xếp, giả sử stck1 và stck2.
  2. Duyệt qua danh sách đầu tiên và đẩy một bản sao của mỗi nút bạn đi qua trong stck1.
  3. Tương tự như bước hai nhưng lần này đi qua danh sách thứ 2 và đẩy bản sao của các nút trong stck2.
  4. Bây giờ, bật từ cả hai ngăn xếp và kiểm tra xem hai nút có bằng nhau hay không, nếu có, hãy giữ một tham chiếu đến chúng. Nếu không, thì các nút trước đó bằng nhau thực sự là điểm hợp nhất mà chúng tôi đang tìm kiếm.

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

Đây là giải pháp đơn giản, Không cần thiết để xem toàn bộ danh sách.

nếu nút có cấu trúc của bạn có ba trường như

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

giả sử bạn có hai phần đầu (head1 và head2) trỏ đến phần đầu của hai danh sách.

Duyệt qua cả danh sách theo cùng một tốc độ và đặt cờ = 1 (cờ đã truy cập) cho nút đó,

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

0

Còn cái này thì sao:

  1. Nếu bạn chỉ được phép duyệt qua mỗi danh sách một lần, bạn có thể tạo một nút mới, duyệt qua danh sách đầu tiên để mọi nút đều trỏ đến nút mới này và duyệt qua danh sách thứ hai để xem có nút nào đang trỏ đến nút mới của bạn không ( đó là điểm hợp nhất của bạn). Nếu đường truyền thứ hai không dẫn đến nút mới của bạn thì danh sách ban đầu không có điểm hợp nhất.

  2. Nếu bạn được phép xem qua các danh sách nhiều hơn một lần, thì bạn có thể xem qua từng danh sách để tìm độ dài của chúng và nếu chúng khác nhau, hãy bỏ qua các nút "bổ sung" ở đầu danh sách dài hơn. Sau đó, chỉ cần lướt qua cả hai danh sách từng bước một và tìm nút hợp nhất đầu tiên.


1. không chỉ sửa đổi mà còn hủy danh sách đầu tiên. 2. được gợi ý nhiều lần.
greybeard,

0

Các bước trong Java:

  1. Tạo bản đồ.
  2. Bắt đầu duyệt trong cả hai nhánh của danh sách và Đặt tất cả các nút được duyệt qua của danh sách vào Bản đồ bằng cách sử dụng một số thứ duy nhất liên quan đến các Nút (giả sử nút Id) làm Khóa và đặt Giá trị là 1 ở đầu cho tất cả.
  3. Khi có khóa trùng lặp đầu tiên xuất hiện, hãy tăng giá trị cho Khóa đó (giả sử bây giờ giá trị của nó trở thành 2 tức là> 1.
  4. Lấy Khóa có giá trị lớn hơn 1 và đó phải là nút nơi hai danh sách đang hợp nhất.

1
Điều gì sẽ xảy ra nếu chúng ta có chu trình trong phần được hợp nhất?
Rohit

Nhưng đối với các chu trình xử lý lỗi, điều này rất giống câu trả lời của isyi .
greybeard,

0

Chúng tôi có thể giải quyết nó một cách hiệu quả bằng cách giới thiệu trường "isVisited". Đảo ngược danh sách đầu tiên và đặt giá trị "isVisited" thành "true" cho tất cả các nút cho đến khi kết thúc. Bây giờ bắt đầu từ thứ hai và tìm nút đầu tiên nơi cờ là true và Boom, điểm hợp nhất của nó.


0

Bước 1: Tìm độ dài của cả danh sách Bước 2: Tìm điểm khác biệt và di chuyển danh sách có điểm chênh lệch lớn nhất Bước 3: Bây giờ cả hai danh sách sẽ ở vị trí tương tự. Bước 4: Lặp lại danh sách để tìm điểm hợp nhất

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

(Tôi thích danh sách với từng hạng mục bắt đầu một dòng tốt hơn xem xét sử dụng một kiểm tra chính tả..)
lọ

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

Bạn cần thêm một số giải thích cho câu trả lời của bạn. Câu trả lời chỉ có mã có thể bị xóa.
rghome

0

Sử dụng Bản đồ hoặc Từ điển để lưu trữ địa chỉ so với giá trị của nút. nếu địa chỉ tồn tại trong Bản đồ / Từ điển thì giá trị của khóa là câu trả lời. Tôi đã làm điều này:

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

Giải pháp độ phức tạp AO (n). Nhưng dựa trên một giả định.

giả định là: cả hai nút chỉ có số nguyên dương.

logic: biến tất cả các số nguyên của list1 thành số âm. Sau đó, lướt qua list2, cho đến khi bạn nhận được một số nguyên âm. Sau khi tìm thấy => lấy nó, đổi dấu thành tích cực và trả về.

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

Chúng ta có thể sử dụng hai con trỏ và di chuyển theo kiểu sao cho nếu một trong các con trỏ là null, chúng ta sẽ trỏ nó vào đầu danh sách kia và tương tự đối với con trỏ kia, theo cách này nếu độ dài danh sách khác nhau, chúng sẽ gặp nhau trong lần vượt qua thứ hai . Nếu độ dài của list1 là n và list2 là m thì hiệu số của chúng là d = abs (nm). Họ sẽ bao phủ khoảng cách này và gặp nhau tại điểm hợp nhất.
Mã:

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

Bạn có thể thêm các nút của list1vào một tập hợp băm và vòng lặp qua tập thứ hai và nếu bất kỳ nút nào của list2đã có trong tập hợp. Nếu có, thì đó là nút hợp nhất

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

Giải pháp sử dụng 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

Nếu cho phép chỉnh sửa danh sách liên kết,

  1. Sau đó, chỉ cần tạo con trỏ nút tiếp theo của tất cả các nút của danh sách 2 là null.
  2. Tìm giá trị dữ liệu của nút cuối cùng trong danh sách 1. Thao tác này sẽ cung cấp cho bạn nút giao nhau trong một lần duyệt của cả hai danh sách, với "không có logic hi fi".
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.