Saya sudah sering mendengar pertanyaan wawancara ini dan saya berharap mendapatkan pendapat tentang jawaban yang bagus: Anda memiliki file besar 10+ GB dan Anda ingin mengetahui elemen mana yang paling banyak terjadi, apa cara yang baik untuk melakukan ini?
Iterasi dan melacak di peta mungkin bukan ide yang baik karena Anda menggunakan banyak memori, dan melacak sebagai entri bukan pilihan terbaik karena ketika pertanyaan ini diajukan file biasanya sudah ada.
Pikiran lain saya termasuk memisahkan file yang akan diiterasi dan diproses oleh beberapa utas dan kemudian hasilnya digabungkan, tetapi masalah memori untuk peta masih ada.
algorithms
arrays
Menepuk
sumber
sumber
Jawaban:
Ketika Anda memiliki file yang sangat besar dan banyak elemen di dalamnya, tetapi elemen yang paling umum sangat umum - terjadi fraksi waktu - Anda dapat menemukannya dalam waktu linier dengan kata-kata ruang ( konstanta pada notasi sangat kecil, pada dasarnya 2 jika Anda tidak menghitung penyimpanan untuk hal-hal tambahan seperti hashing). Selain itu, ini berfungsi baik dengan penyimpanan eksternal, karena file diproses secara berurutan satu elemen pada satu waktu, dan algoritme tidak pernah "melihat ke belakang". Salah satu cara untuk melakukan ini adalah melalui algoritma klasik oleh Misra dan Gries, lihat catatan kuliah ini . Masalahnya sekarang dikenal sebagai masalah pemukul berat (elemen yang sering menjadi pemukul berat).O ( k ) O ( )>1/k O(k) O()
Asumsi bahwa elemen yang paling sering muncul fraksi dari waktu untuk sejumlah kecil mungkin tampak kuat tetapi diperlukan! Yaitu jika Anda akan memiliki akses berurutan ke file Anda (dan jika file tersebut adalah akses acak besar akan terlalu mahal), algoritma apa pun yang selalu menemukan elemen paling sering dalam jumlah lintasan yang konstan akan menggunakan spasi linear dalam jumlah elemen . Jadi jika Anda tidak berasumsi sesuatu tentang input Anda tidak bisa mengalahkan tabel hash. Asumsi bahwa unsur yang paling sering sangat sering adalah mungkin cara paling alami untuk menyiasati hasil negatif.k>1/k k
Berikut ini adalah sketsa untuk , yaitu ketika ada elemen tunggal yang muncul lebih dari separuh waktu. Kasus khusus ini dikenal sebagai algoritma suara terbanyak dan disebabkan oleh Boyer dan Moore. Kami akan menyimpan satu elemen dan satu hitungan. Inisialisasi penghitungan ke 1 dan menyimpan elemen pertama file. Kemudian proses file secara berurutan:k=2
Sedikit pemikiran tentang prosedur ini akan meyakinkan Anda bahwa jika ada elemen "mayoritas", yaitu elemen yang terjadi lebih dari separuh waktu, maka elemen tersebut akan menjadi elemen yang disimpan setelah seluruh file diproses.
Untuk umum , Anda tetap elemen dan jumlah, dan Anda menginisialisasi elemen untuk pertama elemen yang berbeda dari file dan jumlah untuk jumlah kali masing-masing elemen muncul sebelum Anda melihat th elemen yang berbeda. Kemudian Anda menjalankan prosedur yang sama: jumlah elemen meningkat setiap kali ditemukan, semua jumlah elemen berkurang jika elemen yang tidak disimpan ditemukan, dan ketika beberapa jumlah adalah nol, elemen tersebut dikeluarkan untuk mendukung elemen file saat ini. Ini adalah algoritma Misra-Gries.k - 1 k - 1 k kk k−1 k−1 k k
Anda tentu saja dapat menggunakan tabel hash untuk mengindeks elemen yang disimpan . Pada penghentian, algoritma ini dijamin untuk mengembalikan elemen yang terjadi lebih dari fraksi waktu. Ini pada dasarnya adalah yang terbaik yang dapat Anda lakukan dengan algoritma yang membuat jumlah terus-menerus melewati file dan hanya menyimpan kata-kata .1 / k O ( k )k−1 1/k O(k)
Satu hal terakhir: setelah Anda menemukan calon "pemukul berat" (yaitu elemen sering), Anda dapat membuat satu lagi melewati file untuk menghitung frekuensi setiap elemen. Dengan cara ini Anda dapat memberi peringkat elemen di antara satu sama lain dan memverifikasi apakah semuanya terjadi lebih dari fraksi waktu (jika ada kurang dari elemen tersebut, beberapa elemen yang dikembalikan oleh algoritma mungkin positif palsu ).1 / k k - 1k 1/k k−1
sumber
Jawaban yang jelas tentu saja untuk menjaga peta hash dan menyimpan counter dari terjadinya elemen saat Anda menelusuri file seperti yang Nejc sudah sarankan. Ini adalah (dalam hal kompleksitas waktu) solusi optimal.
Namun, jika persyaratan ruang Anda ketat, Anda dapat melakukan pengurutan eksternal pada file dan kemudian menemukan menjalankan elemen yang sama berurutan. Yang berikut harus memiliki jejak memori yang konstan dan dapat dilakukan diΘ(nlogn).
sumber
Jika elemen yang paling umum lebih umum daripada elemen umum berikutnya dengan margin yang substansial, dan jumlah elemen yang berbeda kecil dibandingkan dengan ukuran file, Anda dapat secara acak mencicipi beberapa elemen dan mengembalikan elemen yang paling umum dalam sampel Anda.
sumber