Reverse Nodes in k-Group
Linked list satu arah disimpan dalam dua array dengan panjang yang sama. Node i menyimpan values[i] dan terhubung ke node next[i]; -1 menandai akhir list, dan head adalah node 0. Node dapat disimpan dalam urutan apa pun, jadi ikuti tautannya, bukan urutan array.
Balik urutan list dalam kelompok yang masing-masing terdiri dari k node: k node pertama menjadi terbalik, lalu k node berikutnya, dan seterusnya. Kelompok terakhir yang berisi kurang dari k node tetap mempertahankan urutannya. Kembalikan nilai-nilainya dalam urutan list yang baru.
Fungsi
- nextinteger-array
- indeks node yang ditautkan oleh setiap node, atau -1 untuk node terakhir
- valuesinteger-array
- nilai yang disimpan oleh setiap node
- kinteger
- jumlah node yang perlu dibalik di setiap grup
- Mengembalikaninteger-array
- nilai-nilai dalam urutan daftar baru
Batasan
1 ≤ L ≤ 5000, denganLadalah panjangnextdanvalues.-1000 ≤ values[i] ≤ 10001 ≤ k ≤ L- Setiap
next[i]bernilai-1atau indeks node dari0hinggaL-1. - Dimulai dari simpul
0, list mengunjungi setiap simpul tepat satu kali lalu mencapai-1. Tidak ada siklus.
Contoh
- Input
- next = [2, 3, 4, -1, 1]values = [1, 4, 2, 5, 3]k = 2
- Output
- [2, 1, 4, 3, 5]
- Penjelasan
- list tersebut terbaca sebagai
1, 2, 3, 4, 5(node0, 2, 4, 1, 3). Pasangan1, 2dan3, 4dibalik, dan5sendiri lebih pendek daripadak = 2, jadi tetap di urutan terakhir.
- Input
- next = [5, 3, 6, -1, 7, 2, 4, 1]values = [10, 70, 30, 80, 50, 20, 40, 60]k = 3
- Output
- [30, 20, 10, 60, 50, 40, 70, 80]
- Penjelasan
- list tersebut berbunyi
10, 20, ..., 80. Grup10, 20, 30dan40, 50, 60dibalik.70, 80lebih pendek darik = 3, jadi urutannya tetap.
- Input
- next = [2, -1, 1]values = [7, 9, 3]k = 3
- Output
- [9, 3, 7]
- Penjelasan
- array berisi
7, 9, 3, tetapi list berisi7, 3, 9. Denganksama dengan panjangnya, seluruh list menjadi satu kelompok dan hasilnya terbalik:9, 3, 7.
Pertanyaan lanjutan
Bisakah kamu menulisnya secara rekursif, dengan membalik satu kelompok dan melakukan rekursi pada sisa list? Berapa banyak memori tambahan yang digunakan?
Petunjuk
Buka satu per satu. Setiap petunjuk mengungkap sedikit lebih banyak.
Membalik seluruh list memerlukan penelusuran dengan dua pointer, node sebelumnya dan node saat ini, sambil membalik setiap tautan yang dilewati. Apa yang berubah jika penelusuran harus berhenti setelah
knode dan bagian list yang tersisa harus tetap terhubung?Sebelum kamu membalik sebuah grup, maju
klangkah untuk memeriksa apakah adaknode; jika tidak, biarkan sisanya. Node tempat kamu berhenti berada tepat setelah grup, dan node pertama grup harus berakhir dengan terhubung ke node tersebut.Pertahankan node terakhir dari bagian yang sudah selesai. Setelah membalik sebuah grup, arahkan node tersebut ke node pertama baru dari grup itu (untuk grup pertama, node tersebut adalah head yang baru). Node pertama lama dari grup tersebut sekarang menjadi node terakhir dari bagian yang sudah selesai.
Solusi
Membalik seluruh list memerlukan satu kali lintasan untuk membalik tautan. Di sini, pembalikan berhenti setiap k node, dan setiap grup yang dibalik harus disambungkan ke bagian sebelumnya dan node-node setelahnya. Kamu bisa menyalin nilainya ke dalam array lalu membalik blok, atau menyambungkan ulang setiap grup langsung di tempat dengan memori tambahan O(1).
Salin nilainya dan balik urutan setiap blok
Intuisi
Telusuri dari node 0 dengan node = next[node] dan salin nilainya ke dalam array sesuai urutan list. Kelompoknya kini berupa blok indeks 0 sampai k-1, k sampai 2k-1, dan seterusnya: balik setiap blok yang ukurannya pas dan biarkan blok terakhir yang lebih pendek tetap seperti semula. Proses ini memerlukan waktu O(L) dan memori tambahan O(L), serta tidak pernah menyentuh link.
Algoritma
- Telusuri dari node
0hingga-1dan tambahkanvalues[node]ke array. - Untuk
start = 0, k, 2k, ...selamastart + k ≤ L: balik urutan blok dari indeksstarthinggastart+k-1. - Biarkan blok yang lebih pendek di akhir tetap seperti semula.
- Kembalikan array.
def reverseKGroup(next, values, k):
# Read the values in list order.
order = []
node = 0
while node != -1:
order.append(values[node])
node = next[node]
# Reverse every full block of k; a shorter last block stays as it is.
for start in range(0, len(order) - k + 1, k):
order[start:start + k] = order[start:start + k][::-1]
return orderBalikkan setiap grup di tempatnya dengan menghubungkan ulang
Intuisi
Untuk membalik seluruh list, telusuri list dengan prev dan node, lalu tetapkan next[node] = prev. Satu grup menggunakan perulangan yang sama sebanyak k kali, dengan prev dimulai dari after, simpul tepat setelah grup. Simpul pertama grup menjadi simpul terakhir dan terhubung ke after, sehingga bagian list lainnya tetap tersambung.
Hitung k simpul sebelum membaliknya: jika kamu mencapai -1 lebih dulu, sisanya adalah grup pendek dan dibiarkan. Setelah dibalik, prev menjadi simpul pertama yang baru dalam grup. Hubungkan simpul terakhir dari grup sebelumnya ke simpul itu, atau jadikan simpul itu sebagai head untuk grup pertama. Simpul pertama grup yang lama kini menjadi simpul terakhir dari bagian yang sudah selesai.
Setiap simpul dikunjungi dua kali, sekali untuk menghitung dan sekali untuk membalik: waktu O(L) dan penggunaan memori beberapa bilangan bulat (O(L) di R, yang menyalin vektor tautan saat pertama kali diubah).
Algoritma
- Mulai dengan
head = 0,prevTail = -1,groupStart = 0. - Telusuri
klangkah darigroupStartkeafter; jika kamu mencapai-1terlebih dahulu, lanjutkan ke langkah 5. - Dengan
prev = afterdannode = groupStart, ulangi sebanyakkkali: simpannext[node], aturnext[node] = prev, lalu majukan keduanya. - Jika
prevTailadalah-1, aturhead = prev; jika tidak, aturnext[prevTail] = prev. AturprevTail = groupStart,groupStart = after; lanjutkan ke langkah 2. - Kumpulkan nilai dari
head.
def reverseKGroup(next, values, k):
head = 0 # the list's head; changes after the first group
prev_tail = -1 # last node of the groups already reversed
group_start = 0
while True:
# Find the node right after this group, or stop if fewer than k remain.
after, count = group_start, 0
while after != -1 and count < k:
after = next[after]
count += 1
if count < k:
break
# Turn the group's k links around. Its first node ends up last
# and links to the node after the group.
prev, node = after, group_start
for _ in range(k):
following = next[node]
next[node] = prev
prev, node = node, following
# prev is the group's new first node: hang it after the previous group.
if prev_tail == -1:
head = prev
else:
next[prev_tail] = prev
prev_tail = group_start
group_start = after
# Walk the relinked list from its head.
result = []
node = head
while node != -1:
result.append(values[node])
node = next[node]
return result
Jebakan dan kasus tepi
- Membalik kelompok terakhir yang pendek. Hitung
knode sebelum membaliknya; tautan yang sudah dibalik tidak dapat dikembalikan tanpa proses lain. - Memulai pembalikan dengan
prev = -1, seperti pada pembalikan penuh. Bagian akhir yang pendek akan terlepas: contoh pertama menghasilkan2, 1, 4, 3. - Tidak menghubungkan node terakhir dari kelompok sebelumnya ke node pertama yang baru. Node itu masih menunjuk ke node pertama yang lama, sehingga
k-1node menghilang. - Membaca jawaban dari node
0, atau membacavaluesdari kiri ke kanan. Setelah kelompok berisik ≥ 2dibalik, node0bukan lagi head, dan urutan array tidak pernah sama dengan urutan list. - Menggunakan indeks mulai dari 0 di Lua dan R, yang array-nya dimulai dari 1. Pertahankan indeks node berbasis 0 dan baca
next[node + 1].
Pertanyaan yang sering diajukan3
Berapa kompleksitas waktu dan ruang untuk membalik node dalam kelompok berukuran k?
Proses ini berjalan dalam waktu O(L) untuk list yang terdiri dari L node: setiap node dihitung satu kali dan dibalik satu kali. Versi in-place menggunakan memori tambahan O(1); menyalin nilainya ke dalam array menggunakan O(L).
Apa yang terjadi pada grup terakhir jika jumlah node-nya kurang dari k?
Urutannya tetap seperti semula. Hitung node k sebelum membalik setiap kelompok. Jika kamu mencapai akhir list terlebih dahulu, biarkan sisanya seperti semula.
Mengapa solusi untuk masalah ini menggunakan node dummy?
Dengan object node, node dummy sebelum head memberi grup pertama sebuah node di depannya, sehingga satu baris menghubungkan setiap grup ke bagian yang sudah selesai. Dengan array tautan, prevTail yang tetap bernilai -1 sampai grup pertama selesai melakukan hal yang sama.
Soal serupa
Soal yang memakai ide yang sama. Mengerjakan dua atau tiga di antaranya membuat polanya melekat.
def reverseKGroup(next, values, k):
# Tulis kodemu di siniTes #1
Tes #2
Tes #3
Argumen
next = [2, 3, 4, -1, 1] values = [1, 4, 2, 5, 3] k = 2
Output yang diharapkan
[2, 1, 4, 3, 5]