Saya diberi masalah berikut saat wawancara:
Memberikan string yang berisi beberapa campuran parens (bukan kurung atau kurung kurawal - hanya parens) dengan karakter alfanumerik lainnya, identifikasi semua paren yang tidak memiliki paren yang cocok.
Misalnya, dalam string ") (ab))", indeks 0 dan 5 berisi parens yang tidak memiliki paren yang cocok.
Saya mengedepankan solusi O (n) yang berfungsi menggunakan memori O (n), menggunakan stack dan melalui string sekali menambahkan parens ke stack dan menghapusnya dari stack setiap kali saya menemukan paren penutup dan bagian atas stack berisi sebuah paren pembuka.
Setelah itu, pewawancara mencatat bahwa masalahnya dapat diselesaikan dalam waktu linier dengan memori konstan (seperti, tidak ada penggunaan memori tambahan selain apa yang diambil oleh input.)
Saya bertanya bagaimana dan dia mengatakan sesuatu tentang melalui string sekali dari kiri mengidentifikasi semua parens terbuka, dan kemudian kedua kalinya dari kanan mengidentifikasi semua parens dekat .... atau mungkin sebaliknya. Saya tidak benar-benar mengerti dan tidak ingin memintanya untuk memegang saya.
Adakah yang bisa menjelaskan solusi yang dia sarankan?
sumber
Jawaban:
Anda dapat menjaga prinsip dasar algoritma yang Anda gunakan. Anda melewatkan peluang untuk pengoptimalan memori.
Jadi apa isi tumpukan ini? Ini tidak akan mengandung
()
(tanda kurung buka diikuti oleh tanda kurung tutup), karena setiap kali)
muncul Anda pop the(
bukannya mendorong)
. Jadi tumpukan selalu dalam bentuk)…)(…(
- sekelompok kurung penutup diikuti oleh sekelompok kurung pembuka.Anda tidak perlu tumpukan untuk mewakili ini. Ingat saja jumlah tanda kurung tutup dan jumlah tanda kurung buka.
Jika Anda memproses string dari kiri ke kanan, menggunakan dua penghitung ini, yang Anda miliki pada akhirnya adalah jumlah kurung penutup yang tidak cocok dan jumlah kurung pembuka yang tidak cocok.
Singkatnya: proses string dari kiri ke kanan. Pertahankan counter tanda kurung pembuka yang tidak cocok. Jika Anda melihat tanda kurung buka, tambahkan penghitung. Jika Anda melihat tanda kurung penutup dan penghitungnya bukan nol, turunkan penghitungnya. Jika Anda melihat tanda kurung penutup dan penghitung adalah nol, output indeks saat ini sebagai tanda kurung penutupan tidak cocok.
Nilai akhir dari penghitung adalah jumlah tanda kurung pembuka yang tidak cocok, tetapi ini tidak memberi Anda posisi mereka. Perhatikan bahwa masalahnya simetris. Untuk daftar posisi kurung pembuka yang tidak cocok, jalankan saja algoritma di arah yang berlawanan.
Latihan 1: tulis ini dalam notasi formal (matematika, kodesemu atau bahasa pemrograman favorit Anda).
Latihan 2: yakinkan diri Anda bahwa ini adalah algoritma yang sama dengan Apass.Jack , baru saja dijelaskan secara berbeda.
sumber
(()
.Karena kita bisa mengabaikan semua karakter alfanumerik, kita akan menganggap string hanya berisi tanda kurung mulai sekarang. Seperti dalam pertanyaan, hanya ada satu jenis kurung, "()".
Jika kita terus menghapus tanda kurung yang seimbang sampai tidak ada lagi tanda kurung yang seimbang dapat dihapus, semua tanda kurung yang tersisa harus terlihat seperti ")) ...) ((...," yang semuanya tanda kurung tidak seimbang. Pengamatan ini menunjukkan bahwa kita harus menemukan terlebih dahulu titik balik itu) , sebelum itu kami hanya memiliki kurung tutup yang tidak seimbang dan setelah itu kami memiliki kurung pembuka yang tidak seimbang saja.
Di sini adalah algoritma. Singkatnya, ini menghitung titik balik pertama. Kemudian output kurung penutup ekstra, memindai string dari awal ke kanan hingga titik balik. Secara simetris, ini menghasilkan kurung pembuka ekstra, pemindaian dari ujung ke kiri sampai titik balik.
str
Inisialisasi
turning_point=0, maximum_count=0, count=0
. Untuk setiapi
dari0
ken-1
melakukan hal berikut.str[i] = ')'
, tambahkan 1 kecount
; jika tidak, kurangi 1.count > maximum_count
, aturturning_point=i
danmaximum_count=count
.Sekarang
turning_point
adalah indeks dari titik baliknya.Setel ulang
maximum_count=0, count=0
. Untuk setiapi
dari0
keturning_point
melakukan hal berikut.str[i] = ')'
, tambahkan 1 kecount
; jika tidak, kurangi 1.count > maximum_count
diaturmaximum_count = count
. Outputi
sebagai indeks kurung tutup tidak seimbang.Setel ulang
maximum_count=0, count=0
. Untuk setiapi
darin-1
keturning_point+1
bawah melakukan hal berikut.str[j] = '('
, tambahkan 1 kecount
; jika tidak, kurangi 1.count > maximum_count
diaturmaximum_count = count
. Outputi
sebagai indeks kurung pembuka tidak seimbang.Jika kita menganalisis algoritma di atas, kita akan melihat bahwa, pada kenyataannya, kita tidak perlu menemukan dan menggunakan titik balik sama sekali. Pengamatan yang bagus bahwa semua kurung tutup tidak seimbang terjadi sebelum semua kurung buka tidak seimbang dapat diabaikan meskipun menarik.
Berikut adalah kode dalam Python .
Tekan saja "lari" untuk melihat beberapa hasil tes.
Latihan 1. Tunjukkan bahwa algoritma di atas akan menampilkan satu set tanda kurung dengan kardinalitas terkecil sehingga tanda kurung yang tersisa seimbang.
Masalah 1. Bisakah kita menggeneralisasi algoritma ke kasus ketika string berisi dua jenis tanda kurung seperti "() []"? Kita harus menentukan bagaimana mengenali dan memperlakukan situasi baru, kasus interleaving, "([)]".
sumber