Frekuensi Kata dengan Memesan dalam Kompleksitas O (n)

11

Selama wawancara untuk posisi pengembang Java, saya ditanya hal berikut:

Tulis fungsi yang membutuhkan dua params:

  1. String yang mewakili dokumen teks dan
  2. bilangan bulat yang menyediakan jumlah item untuk dikembalikan.

Menerapkan fungsi sedemikian rupa sehingga mengembalikan daftar String yang dipesan berdasarkan frekuensi kata, kata yang paling sering muncul terlebih dahulu. Solusi Anda harus dijalankan dalam waktu di mana adalah jumlah karakter dalam dokumen.nO(n)n

Berikut ini adalah apa yang saya jawab (dalam pseudocode), ini bukan melainkan waktu karena jenisnya. Saya tidak tahu bagaimana melakukannya waktu. O ( n log n ) O ( n )O(n)O(nlogn)O(n)

wordFrequencyMap = new HashMap<String, Integer>();
words = inputString.split(' ');

for (String word : words) {
  count = wordFrequencyMap.get(word);
  count = (count == null) ? 1 : ++count;
  wordFrequencyMap.put(word, count);
}

return wordFrequencyMap.sortByValue.keys

Apakah ada yang tahu atau ada yang bisa memberi saya petunjuk?

pengguna2712937
sumber
1
Gunakan tabel hash.
Yuval Filmus
Menggunakan hashtable tidak menyelesaikan masalah. Selanjutnya, hashtable adalah warisan Java.
user2712937
Tabel hash biasanya merupakan trik untuk menurunkan kompleksitas dari ke . Kalaupun mereka peninggalan Jawa, apa pun artinya. Saya belum memeriksa kasus khusus ini, jadi Anda mungkin benar. O ( n )O(nlogn)O(n)
Yuval Filmus
@YuvalFilmus. Terima kasih tetapi tabel hash hampir sama dengan peta hash, yang sudah saya gunakan (perbedaan utama antara 2 data struct adalah sinkronisasi, yang tidak berlaku di sini). Log (n) di tambang berasal dari pengurutan nilai dalam peta hash.
user2712937
3
Omong-omong, situs ini berfokus pada konsep dan algoritma, bukan pada kode. Oleh karena itu, biasanya kami akan meminta Anda untuk menghapus kode Java dan memberikan deskripsi konseptual tentang pendekatan Anda (mungkin dengan pseudocode tingkat tinggi yang ringkas jika diperlukan). Juga, di situs ini pertanyaan yang relevan adalah struktur data dan algoritma apa yang digunakan; API Java tertentu di luar topik untuk situs ini (tetapi Anda dapat menanyakannya di StackOverflow), dan demikian pula, apakah HashtableJava warisan atau tidak benar-benar tidak relevan untuk tujuan situs ini.
DW

Jawaban:

10

Saya menyarankan variasi penghitungan distribusi:

  1. Baca teks dan masukkan semua kata yang dijumpai ke dalam sebuah trie , pertahankan setiap node dalam hitungan, seberapa sering kata yang diwakili oleh simpul ini terjadi. Juga melacak jumlah kata tertinggi katakan maxWordCound. -O(n)
  2. Inisialisasi array ukuran maxWordCount. Jenis entri adalah daftar string. - , karena hitungannya tidak boleh lebih tinggi.O(n)
  3. Traverse trie dan untuk setiap node tambahkan string yang sesuai ke entri array yang ditunjukkan oleh hitungan. - , karena panjang total string dibatasi oleh .nO(n)n
  4. Lintasi array dalam urutan menurun dan output jumlah string yang diinginkan. - , karena itu terikat pada ukuran dan jumlah data dalam array.O(n)

Anda mungkin dapat mengganti trie dengan struktur data lain di fase pertama.

FrankW
sumber
+1, meskipun saya tidak yakin tentang ini. Ini adalah O (n) karena jumlah kata yang dikembalikan dibatasi oleh n, jumlah karakter, tetapi apakah ini pertanyaannya? Atau hasil terlepas dari jumlah kata yang dikembalikan?
Nikos M.
n
@ Raphael, yap benar saya sedang memikirkan hal ini karena ditanya dalam sebuah wawancara, kemungkinan trik dalam pertanyaan ..
Nikos M.
Saya bertanya-tanya apakah ada algoritma waktu linear yang efisien ruang.
saadtaame
3
O(nlgn)O(n)
3

Pengumpulan jumlah kejadian adalah O (n), jadi triknya adalah hanya menemukan jumlah kejadian teratas.

Heap adalah cara umum untuk mengagregasi nilai k teratas, walaupun metode lain dapat digunakan (lihat https://en.wikipedia.org/wiki/Partial_sorting ).

Dengan asumsi k adalah param kedua di atas, dan itu adalah konstanta dalam pernyataan masalah (tampaknya):

  1. Buat tiga kata dengan jumlah kejadian pada setiap node.
  2. Inisialisasi tumpukan ukuran k.
  3. Lintasi trie dan min-probe / masukkan setiap pasangan (daun, jumlah-kejadian) di tumpukan top-k.
  4. Keluarkan daun atas k dan hitung (ini sebenarnya agak sakit karena Anda perlu pointer orangtua untuk memetakan setiap daun kembali ke kata).

Karena ukuran heap adalah konstan, operasi heap adalah O (1), jadi langkah 3 adalah O (n).

Tumpukan juga dapat dipertahankan secara dinamis saat membangun trie.

KWillets
sumber
2

O(nlogn)Θ(n)Ω(n2)


Yang berikut salah ; Saya meninggalkannya di sini untuk sementara waktu untuk tujuan ilustrasi.

O(n)Σn

  1. Bangun pohon sufiks teks, misalnya dengan algoritma Ukkonen .

    Jika konstruksi belum melakukan ini, tambahkan jumlah daun yang dapat dijangkau ke setiap simpul (bagian dalam).

  2. Lintasi pohon dari akar dan potong semua cabang di ruang pertama (putih).

  3. Lintasi pohon dan urutkan daftar anak-anak dari setiap simpul berdasarkan jumlah daunnya.

  4. Hasil pohon (daun dari kiri ke kanan) sekarang daftar semua kata, diurutkan berdasarkan frekuensi.

Mengenai runtime:

  1. O(n)Θ
  2. nn
  3. nO(|Σ|log|Σ|)=O(1)
  4. O(n)O(n)

Batas yang lebih tepat dapat diperoleh dengan parametrising runtime dengan jumlah kata yang berbeda; jika ada sedikit, pohon itu kecil setelah 2.

Raphael
sumber
Algoritma salah (tidak mengurutkan). Saya tidak lagi yakin waktu linear bahkan mungkin.
Raphael
1

HashMap1..nO(n)O(n)

O(n)O(n)O(n)

O(n)O(n)

DW
sumber
Θ(n)Ω(n2)
Saya tidak dapat berbicara untuk pewawancara, tetapi saya ragu untuk menggunakan kecerobohan mereka sebagai alasan untuk hal yang sama. Juga, situs ini adalah tentang sains (seperti yang Anda komentari di atas), bukan tentang melambaikan tangan "bagaimana saya akan dibayar lebih cepat" trik pemrograman.
Raphael
Selama pemahaman ini dibuat eksplisit, saya baik-baik saja dengan itu. Saya telah melihat terlalu banyak pertanyaan di sini yang dibuat dalam kebingungan karena beberapa "pemahaman" implisit mempromosikan ide-ide yang salah.
Raphael
0

Solusi berbasis Hashtable

Ω(n2)n

nΩ(n)

O(1)O(n)O(n2)n

Asumsinya adalah bahwa algoritma hashing adalah linear dalam waktu dalam kaitannya dengan jumlah karakter.

Solusi berbasis radix

O(kN)kNnkO(n)

2nnO(n)

Beberapa kata terpanjang teratas dalam bahasa Inggris panjangnya sangat panjang , tetapi kemudian seseorang dapat membatasi panjang kata pada angka yang masuk akal (misalnya 30 atau lebih kecil) dan memotong kata-kata yang menerima margin kesalahan yang mungkin menyertainya.

Omer Iqbal
sumber
Θ(n)Θ(n)
O(n+n)O(n2)
(3) Apa pun fungsi hash yang Anda pilih, saya dapat menghasilkan input di mana fungsi spesifik tersebut menurun. Dan memilih fungsi hash setelah mengetahui input biasanya bukan opsi. (Dan ingat bahwa komentar yang mungkin Anda bahas adalah tentang kasus terburuk, bukan kasus biasa.)
FrankW
O(n2)
O(n2)O(1)Ω(1)O(1)O(1)