Pertanyaan ini mungkin sudah lama, tapi saya tidak bisa menemukan jawabannya.
Katakanlah, ada dua daftar dengan panjang yang berbeda, bergabung pada satu titik ; bagaimana kita tahu dimana titik penggabungannya?
Kondisi:
- Kami tidak tahu panjangnya
- Kita harus mengurai setiap daftar hanya sekali.
Jawaban:
Jika
algoritma berikut akan menjadi solusinya.
Pertama, angkanya. Asumsikan daftar pertama panjang
a+c
dan daftar kedua panjangb+c
, di manac
panjang "ekor" mereka (setelah titik gabungan). Mari kita tunjukkan sebagai berikut:Karena kita tidak mengetahui panjangnya, kita akan menghitung
x
dany
tanpa iterasi tambahan; Anda akan melihat caranya.Kemudian, kami mengulang setiap daftar dan membalikkannya saat melakukan iterasi! Jika kedua iterator mencapai titik penggabungan pada saat yang sama, maka kami menemukannya hanya dengan membandingkan. Jika tidak, satu penunjuk akan mencapai titik gabungan sebelum penunjuk lainnya.
Setelah itu, ketika iterator lain mencapai titik penggabungan, itu tidak akan dilanjutkan ke ekor yang sama. Sebaliknya akan kembali ke awal awal daftar yang telah mencapai titik gabungan sebelumnya! Jadi, sebelum mencapai akhir dari daftar yang diubah (yaitu awal awal dari daftar lainnya), dia akan membuat
a+b+1
iterasi total. Sebut sajaz+1
.Penunjuk yang mencapai titik gabungan pertama, akan terus melakukan iterasi, hingga mencapai akhir daftar. Jumlah iterasi yang dibuat harus dihitung dan sama dengan
x
.Kemudian, penunjuk ini mengulang kembali dan membalik daftar lagi. Tapi sekarang itu tidak akan kembali ke awal daftar semula! Sebaliknya, ini akan pergi ke awal daftar lainnya! Jumlah iterasi yang dibuat harus dihitung dan sama dengan
y
.Jadi kita tahu angka-angka berikut:
Dari mana kami menentukan itu
Yang memecahkan masalah.
sumber
Berikut ini adalah yang terbesar dari semua yang pernah saya lihat - O (N), tidak ada penghitung. Saya mendapatkannya saat wawancara dengan kandidat SN di VisionMap .
Buatlah penunjuk antar seperti ini: ia maju setiap kali sampai akhir, lalu melompat ke awal daftar yang berlawanan, dan seterusnya. Buat dua ini, menunjuk ke dua kepala. Tingkatkan tiap pointer sebanyak 1 setiap kali, sampai bertemu. Ini akan terjadi setelah satu atau dua operan.
Saya masih menggunakan pertanyaan ini dalam wawancara - tetapi untuk melihat berapa lama seseorang memahami mengapa solusi ini berhasil.
sumber
a-b-c-x-y-z
danp-q-x-y-z
. jalur penunjuk pertamaa,b,c,x,y,z,p,q,x
, jalur penunjuk keduap,q,x,y,z,a,b,c,x
Jawaban Pavel membutuhkan modifikasi daftar serta mengulang setiap daftar dua kali.
Berikut adalah solusi yang hanya membutuhkan iterasi setiap daftar dua kali (pertama kali menghitung panjangnya; jika panjangnya diberikan, Anda hanya perlu mengulanginya sekali).
Idenya adalah mengabaikan entri awal dari daftar yang lebih panjang (titik gabungan tidak boleh ada di sana), sehingga kedua penunjuk memiliki jarak yang sama dari akhir daftar. Kemudian pindahkan ke depan sampai menyatu.
Ini secara asimtotik sama (waktu linier) dengan jawaban saya yang lain tetapi mungkin memiliki konstanta yang lebih kecil, jadi mungkin lebih cepat. Tapi saya pikir jawaban saya yang lain lebih keren.
sumber
Nah, jika Anda tahu bahwa keduanya akan bergabung:
Katakanlah Anda mulai dengan:
1) Pergi melalui pengaturan daftar pertama setiap penunjuk berikutnya ke NULL.
Sekarang kamu punya:
2) Sekarang pergi melalui daftar kedua dan tunggu sampai Anda melihat NULL, itu adalah titik penggabungan Anda.
Jika Anda tidak dapat memastikan bahwa mereka bergabung, Anda dapat menggunakan nilai sentinel untuk nilai penunjuk, tapi itu tidak elegan.
sumber
Jika kita bisa mengulang daftar tepat dua kali, maka saya bisa memberikan metode untuk menentukan titik penggabungan:
sumber
Berikut solusinya, secara komputasi cepat (mengulang setiap daftar satu kali) tetapi menggunakan banyak memori:
sumber
Anda dapat menggunakan satu set Node. Iterasi melalui satu daftar dan tambahkan setiap Node ke set. Kemudian lakukan iterasi melalui daftar kedua dan untuk setiap iterasi, periksa apakah Node ada di set. Jika ya, Anda telah menemukan titik penggabungan Anda :)
sumber
Ini bisa dibilang melanggar ketentuan "parse setiap daftar hanya sekali", tetapi menerapkan algoritme kura - kura dan kelinci (digunakan untuk menemukan titik penggabungan dan panjang siklus daftar siklik) sehingga Anda mulai dari Daftar A, dan ketika Anda mencapai NULL di akhir Anda berpura-pura itu adalah penunjuk ke awal daftar B, sehingga menciptakan tampilan daftar siklik. Algoritme kemudian akan memberi tahu Anda dengan tepat seberapa jauh daftar A penggabungan (variabel 'mu' menurut deskripsi Wikipedia).
Selain itu, nilai "lambda" memberi tahu Anda panjang daftar B, dan jika Anda mau, Anda dapat menghitung panjang daftar A selama algoritme (saat Anda mengarahkan ulang tautan NULL).
sumber
Mungkin saya terlalu menyederhanakan ini, tetapi hanya mengulang daftar terkecil dan menggunakan node terakhir
Link
sebagai titik penggabungan?Jadi, di mana
Data->Link->Link == NULL
titik akhirnya, memberiData->Link
sebagai titik penggabungan (di akhir daftar).EDIT:
Oke, dari gambar yang kamu posting tadi kamu parse dua list, yang terkecil dulu. Dengan daftar terkecil Anda dapat mempertahankan referensi ke node berikut. Sekarang, ketika Anda mengurai daftar kedua Anda melakukan perbandingan pada referensi untuk menemukan di mana Referensi [i] adalah referensi di LinkedList [i] -> Link. Ini akan memberikan titik penggabungan. Saatnya menjelaskan dengan gambar (tumpang tindih nilai pada gambar OP).
Anda memiliki daftar tertaut (referensi ditunjukkan di bawah):
A->B->C->D->E
Anda memiliki daftar tertaut kedua:
1->2->
Dengan daftar yang digabungkan, referensi akan menjadi sebagai berikut:
1->2->D->E->
Oleh karena itu, Anda memetakan daftar "kecil" pertama (sebagai daftar gabungan, yang kami hitung memiliki panjang 4 dan daftar utama 5)
Ulangi daftar pertama, pertahankan referensi referensi.
Daftar tersebut akan berisi referensi berikut
Pointers { 1, 2, D, E }
.Kami sekarang melalui daftar kedua:
Tentu, Anda mempertahankan daftar petunjuk baru, tapi itu tidak di luar spesifikasi. Namun daftar pertama diurai tepat satu kali, dan daftar kedua hanya akan diurai sepenuhnya jika tidak ada titik penggabungan. Jika tidak, ini akan berakhir lebih cepat (di titik penggabungan).
sumber
Saya telah menguji kasus penggabungan pada FC9 x86_64 saya, dan mencetak setiap alamat node seperti yang ditunjukkan di bawah ini:
Catatan karena saya telah menyelaraskan struktur node, jadi ketika malloc () sebuah node, alamatnya sejajar w / 16 byte, lihat paling sedikit 4 bit. Bit terkecil adalah 0s, yaitu 0x0 atau 000b. Jadi jika Anda berada dalam kasus khusus yang sama (alamat node selaras) juga, Anda dapat menggunakan minimal 4 bit ini. Misalnya ketika melakukan perjalanan kedua daftar dari kepala ke ekor, setel 1 atau 2 dari 4 bit alamat node kunjungan, yaitu, setel bendera;
Catatan di atas bendera tidak akan mempengaruhi alamat node yang sebenarnya tetapi hanya nilai penunjuk node TERSIMPAN Anda.
Setelah ditemukan seseorang telah mengatur bit flag, maka node pertama yang ditemukan harus menjadi titik penggabungan. setelah selesai, Anda akan mengembalikan alamat node dengan menghapus bit bendera yang telah Anda tetapkan. sementara yang penting adalah Anda harus berhati-hati saat melakukan iterasi (misalnya node = node-> next) untuk melakukan pembersihan. ingat Anda telah menetapkan bit bendera, jadi lakukan dengan cara ini
Karena proposal ini akan memulihkan alamat node yang diubah, ini dapat dianggap sebagai "tidak ada modifikasi".
sumber
Mungkin ada solusi sederhana tetapi akan membutuhkan ruang tambahan. Idenya adalah melintasi daftar dan menyimpan setiap alamat dalam peta hash, sekarang melintasi daftar lain dan cocok jika alamat tersebut ada di peta hash atau tidak. Setiap daftar hanya ditelusuri sekali. Tidak ada modifikasi pada daftar mana pun. Panjangnya masih belum diketahui. Ruang bantu yang digunakan: O (n) dengan 'n' adalah panjang list pertama yang dilalui.
sumber
solusi ini mengulang setiap daftar hanya sekali ... tidak ada modifikasi daftar yang diperlukan juga .. meskipun Anda mungkin mengeluh tentang ruang ..
1) Pada dasarnya Anda mengulang dalam list1 dan menyimpan alamat setiap node dalam sebuah array (yang menyimpan nilai int unsigned)
2) Kemudian Anda mengulang list2, dan untuk setiap alamat node ---> Anda mencari melalui array yang Anda temukan cocok atau tidak ... jika Anda melakukannya maka ini adalah node penggabungan
Semoga ini solusi yang valid ...
sumber
Tidak perlu mengubah daftar apa pun. Ada solusi di mana kita hanya perlu melintasi setiap daftar satu kali.
sumber
sumber
Inilah solusi naif, Tidak perlu melintasi seluruh daftar.
jika node terstruktur Anda memiliki tiga bidang seperti
katakanlah Anda memiliki dua kepala (head1 dan head2) yang menunjuk ke head dari dua daftar.
Lintasi kedua daftar dengan kecepatan yang sama dan letakkan bendera = 1 (bendera yang dikunjungi) untuk simpul itu,
sumber
Bagaimana dengan ini:
Jika Anda hanya diperbolehkan melintasi setiap daftar hanya sekali, Anda dapat membuat simpul baru, melintasi daftar pertama untuk memiliki setiap titik simpul ke simpul baru ini, dan melintasi daftar kedua untuk melihat apakah ada simpul yang menunjuk ke simpul baru Anda ( itulah titik penggabungan Anda). Jika traversal kedua tidak mengarah ke node baru Anda, daftar asli tidak memiliki titik penggabungan.
Jika Anda diizinkan melintasi daftar lebih dari satu kali, Anda dapat melintasi setiap daftar untuk menemukan panjangnya dan jika berbeda, hilangkan simpul "ekstra" di awal daftar yang lebih panjang. Kemudian telusuri kedua daftar satu per satu dan temukan node penggabungan pertama.
sumber
Langkah-langkah di Java:
sumber
Kami dapat menyelesaikannya secara efisien dengan memperkenalkan bidang "isVisited". Lintasi daftar pertama dan setel nilai "isVisited" ke "true" untuk semua node hingga akhir. Sekarang mulai dari yang kedua dan temukan node pertama di mana flag benar dan Boom, itu adalah titik penggabungan Anda.
sumber
Langkah 1: temukan panjang kedua daftar Langkah 2: Temukan perbedaan dan pindahkan daftar terbesar dengan perbedaan Langkah 3: Sekarang kedua daftar akan berada pada posisi yang sama. Langkah 4: Iterasi melalui daftar untuk menemukan titik penggabungan
sumber
sumber
Gunakan Peta atau Kamus untuk menyimpan nilai alamat vs node. Jika alamat tersebut sudah ada di Map / Dictionary maka nilai kuncinya adalah jawabannya. Saya melakukan ini:
sumber
Solusi kompleksitas AO (n). Tapi berdasarkan asumsi.
asumsinya adalah: kedua node hanya memiliki bilangan bulat positif.
logika: buat semua bilangan bulat list1 menjadi negatif. Kemudian telusuri list2, sampai Anda mendapatkan bilangan bulat negatif. Setelah ditemukan => ambillah, ubah tandanya kembali menjadi positif dan return.
sumber
Kita dapat menggunakan dua penunjuk dan bergerak dengan cara sedemikian rupa sehingga jika salah satu penunjuk adalah nol, kita mengarahkannya ke kepala daftar lainnya dan sama untuk yang lain, dengan cara ini jika panjang daftar berbeda, mereka akan bertemu di lintasan kedua. . Jika panjang list1 adalah n dan list2 adalah m, selisihnya adalah d = abs (nm). Mereka akan menempuh jarak ini dan bertemu di titik penggabungan.
Kode:
sumber
Anda dapat menambahkan node dari
list1
ke hashset dan loop melalui detik dan jika ada node darilist2
sudah ada di set. Jika ya, maka itu node gabungansumber
Solusi menggunakan javascript
sumber
Jika mengedit daftar tertaut diperbolehkan,
sumber