Saya diberi masalah ini dalam sebuah wawancara. Bagaimana Anda akan menjawabnya?
Rancang struktur data yang menawarkan operasi berikut dalam waktu O (1):
- memasukkan
- menghapus
- mengandung
- dapatkan elemen acak
data-structures
guildner
sumber
sumber
Jawaban:
Pertimbangkan struktur data yang terdiri dari hashtable H dan array A. Kunci hashtable adalah elemen dalam struktur data, dan nilainya adalah posisinya dalam array.
karena array perlu bertambah besar secara otomatis, itu akan diamortisasi O (1) untuk menambahkan elemen, tapi saya rasa tidak apa-apa.
sumber
Pencarian O (1) menyiratkan struktur data berciri .
Dengan perbandingan:
sumber
hashtable.get((int)(Math.random()*hashtable.size()));
Anda mungkin tidak menyukai ini, karena mereka mungkin mencari solusi yang cerdas, tetapi kadang-kadang membayar untuk tetap berpegang pada keinginan Anda ... Tabel hash sudah memenuhi persyaratan - mungkin secara keseluruhan lebih baik daripada yang lain (meskipun jelas dalam konstanta diamortisasi waktu, dan dengan kompromi yang berbeda dengan solusi lain).
Persyaratan yang rumit adalah pemilihan "elemen acak": dalam tabel hash, Anda perlu memindai atau menyelidiki elemen semacam itu.
Untuk pencirian tertutup / pengalamatan terbuka, kemungkinan setiap bucket ditempati adalah
size() / capacity()
, tetapi yang terpenting ini biasanya disimpan dalam kisaran perkalian konstan dengan implementasi tabel hash (misalnya tabel dapat disimpan lebih besar dari isinya saat ini dengan katakanlah 1.2x hingga ~ 10x tergantung pada kinerja / penyetelan memori). Ini berarti rata-rata kami dapat mencari 1,2 hingga 10 ember - benar-benar tidak tergantung pada ukuran total wadah; diamortisasi O (1).Saya bisa membayangkan dua pendekatan sederhana (dan lebih banyak lagi pendekatan fiddly):
telusuri secara linier dari keranjang acak
coba keranjang acak berulang kali sampai Anda menemukan yang terisi
Bukan solusi yang hebat, tetapi mungkin masih merupakan kompromi keseluruhan yang lebih baik daripada overhead memori dan kinerja untuk mempertahankan array indeks kedua setiap saat.
sumber
Solusi terbaik mungkin adalah tabel hash + array, ini sangat cepat dan deterministik.
Tetapi jawaban dengan peringkat terendah (cukup gunakan tabel hash!) Sebenarnya bagus juga!
Orang-orang mungkin tidak menyukai ini karena "kemungkinan putaran tak terbatas", dan saya telah melihat orang yang sangat pintar mengalami reaksi ini juga, tapi itu salah! Peristiwa yang sangat tidak mungkin tidak terjadi begitu saja.
Dengan asumsi perilaku baik dari sumber pseudo-random Anda - yang tidak sulit dibuat untuk perilaku khusus ini - dan tabel hash selalu setidaknya 20% penuh, mudah untuk melihat bahwa:
Tidak akan pernah terjadi jika getRandom () harus mencoba lebih dari 1000 kali. Tidak pernah . Memang, kemungkinan kejadian seperti itu adalah 0,8 ^ 1000, yaitu 10 ^ -97 - jadi kita harus mengulanginya 10 ^ 88 kali agar satu peluang dari satu miliar kejadian itu pernah terjadi sekali. Bahkan jika program ini berjalan penuh waktu di semua komputer manusia sampai Matahari mati, ini tidak akan pernah terjadi.
sumber
Untuk Pertanyaan ini saya akan menggunakan dua Struktur Data
Langkah :-
Kode: -
- Kompleksitas waktu O (1). - Kompleksitas ruang O (N).
sumber
Berikut adalah solusi C # untuk masalah yang saya munculkan beberapa waktu lalu ketika ditanya pertanyaan yang sama. Ini mengimplementasikan Tambah, Hapus, Berisi, dan Acak bersama dengan antarmuka .NET standar lainnya. Bukan berarti Anda perlu menerapkannya secara detail selama wawancara tetapi senang memiliki solusi konkret untuk dilihat ...
sumber
ArgumentException
dengan pesan "Item dengan kunci yang sama telah ditambahkan." akan dilempar (dari kamus indeks yang mendasari).Kita dapat menggunakan hashing untuk mendukung operasi dalam waktu Θ (1).
insert (x) 1) Periksa apakah x sudah ada dengan melakukan pencarian peta hash. 2) Jika tidak ada, masukkan di akhir larik. 3) Tambahkan juga tabel hash, x ditambahkan sebagai kunci dan indeks array terakhir sebagai indeks.
hapus (x) 1) Periksa apakah x ada dengan melakukan pencarian peta hash. 2) Jika ada, temukan indeksnya dan hapus dari peta hash. 3) Tukar elemen terakhir dengan elemen ini dalam array dan hapus elemen terakhir. Swapping dilakukan karena elemen terakhir dapat dihilangkan dalam waktu O (1). 4) Perbarui indeks elemen terakhir di peta hash.
getRandom () 1) Menghasilkan nomor acak dari 0 hingga indeks terakhir. 2) Kembalikan elemen array pada indeks yang dibuat secara acak.
search (x) Lakukan pencarian untuk x di peta hash.
sumber
Meskipun ini jauh lebih tua, tetapi karena tidak ada jawaban di C ++, inilah dua sen saya.
Berikut adalah kode klien untuk menguji solusinya.
sumber
Di C # 3.0 + .NET Framework 4, generik
Dictionary<TKey,TValue>
bahkan lebih baik daripada Hashtable karena Anda dapat menggunakanSystem.Linq
metode ekstensiElementAt()
untuk mengindeks ke dalam array dinamis yang mendasari tempatKeyValuePair<TKey,TValue>
elemen disimpan:Namun, sejauh yang saya tahu, Hashtable (atau keturunan Dictionary-nya) bukanlah solusi nyata untuk masalah ini karena Put () hanya dapat diamortisasi O (1), bukan O (1) yang sebenarnya, karena itu adalah O (N) ) di batas pengubahan ukuran dinamis.
Apakah ada solusi nyata untuk masalah ini? Yang dapat saya pikirkan adalah jika Anda menentukan kapasitas awal Dictionary / Hashtable urutan besarnya melebihi apa yang Anda antisipasi pernah butuhkan, maka Anda mendapatkan operasi O (1) karena Anda tidak perlu mengubah ukuran.
sumber
Saya setuju dengan Anon. Kecuali untuk persyaratan terakhir di mana mendapatkan elemen acak dengan keadilan yang sama diperlukan, semua persyaratan lain dapat ditangani hanya dengan menggunakan DS berbasis Hash tunggal. Saya akan memilih HashSet untuk ini di Jawa. Modulo kode hash suatu elemen akan memberi saya indeks no dari array yang mendasari dalam waktu O (1). Saya dapat menggunakannya untuk menambah, menghapus, dan berisi operasi.
sumber
Bisakah kita melakukan ini menggunakan HashSet dari Java? Ini menyediakan insert, del, search all in O (1) secara default. Untuk getRandom kita dapat menggunakan iterator dari Set yang memberikan perilaku acak. Kita bisa mengulang elemen pertama dari set tanpa mengkhawatirkan elemen lainnya
sumber
sumber
Mengapa kita tidak menggunakan epoch% arraysize untuk menemukan elemen acak. Menemukan ukuran array adalah O (n) tetapi kompleksitas yang diamortisasi akan menjadi O (1).
sumber
Saya pikir kita bisa menggunakan daftar tautan ganda dengan tabel hash. key akan menjadi elemen dan nilai yang terkait akan menjadi node di linklist ganda.
sumber