Saya memiliki array yang tidak disortir . Saya memiliki pertanyaan di mana saya memberikan rentang dan kemudian nilai maksimum dari rentang itu harus dikembalikan. Sebagai contoh:
array[]={23,17,9,45,78,2,4,6,90,1};
query(both inclusive): 2 6
answer: 78
Algoritme atau struktur data mana yang saya buat untuk dengan cepat mengambil nilai maksimum dari rentang apa pun. (Ada banyak pertanyaan)
EDIT: Ini memang versi sederhana dari masalah aktual. Saya dapat memiliki ukuran array sebesar 100000 dan jumlah permintaan hingga 100000. Jadi saya pasti memerlukan beberapa preprocessing yang akan memfasilitasi respon permintaan yang cepat.
algorithms
array
sudeepdino008
sumber
sumber
Jawaban:
Saya pikir Anda bisa membangun semacam pohon biner di mana setiap node mewakili nilai maksimum anak-anaknya:
Maka Anda hanya perlu menemukan cara untuk menentukan node mana yang paling tidak perlu Anda periksa untuk menemukan nilai maksimum dalam rentang yang ditanyakan. Dalam contoh ini, untuk mendapatkan nilai maksimum dalam rentang indeks
[2, 6]
(inklusif) yang Anda milikimax(45, 78, 4)
sebagai gantinyamax(9, 45, 78, 2, 4)
. Saat pohon tumbuh, keuntungannya akan lebih besar.sumber
78
(dan melewatkan2
), karena untuk semua yang tahu indeks6
ada di subtree itu.Untuk melengkapi jawaban ngoaho91.
Cara terbaik untuk mengatasi masalah ini adalah menggunakan struktur data Segment Tree. Ini memungkinkan Anda untuk menjawab pertanyaan seperti di O (log (n)), itu berarti kompleksitas total algoritma Anda akan menjadi O (Q logn) di mana Q adalah jumlah permintaan. Jika Anda menggunakan algoritma naif, kompleksitas totalnya adalah O (Q n) yang jelas lebih lambat.
Namun, ada kelemahan dari penggunaan Pohon Segmen. Membutuhkan banyak memori, tetapi seringkali Anda tidak terlalu peduli dengan memori daripada kecepatan.
Saya akan menjelaskan secara singkat algoritma yang digunakan oleh DS ini:
Pohon segmen hanya kasus khusus dari Pohon Pencarian Biner, di mana setiap node memegang nilai rentang itu ditugaskan. Simpul root, diberikan kisaran [0, n]. Anak kiri diberi kisaran [0, (0 + n) / 2] dan anak kanan [(0 + n) / 2 + 1, n]. Dengan cara ini pohon akan dibangun.
Buat Pohon :
Pohon Permintaan
Jika Anda perlu penjelasan lebih lanjut, beri tahu saya.
BTW, Segment Tree juga mendukung pembaruan elemen tunggal atau serangkaian elemen di O (log n)
sumber
O(log(n))
setiap elemen harus ditambahkan ke pohon. Oleh karena itu, kompleksitas totalnya adalahO(nlog(n))
Algoritma terbaik adalah dalam waktu O (n) seperti di bawah ini mari kita mulai, akhir menjadi indeks batas jangkauan
sumber
max
untuka[i]
dan memulaifor
lingkaran dii+1
.)start
, berhenti diend
). Dan saya setuju, ini adalah yang terbaik untuk pencarian satu kali. Jawaban @ ThijsvanDien hanya lebih baik jika pencarian akan terjadi beberapa kali, karena dibutuhkan waktu lebih lama untuk mengatur awalnya.Solusi berbasis pohon biner / segmen pohon memang menunjuk ke arah yang benar. Orang mungkin keberatan bahwa mereka membutuhkan banyak memori tambahan. Ada dua solusi untuk masalah ini:
Poin pertama adalah bahwa karena pohon sangat terstruktur, Anda dapat menggunakan struktur seperti tumpukan untuk secara implisit mendefinisikan pohon daripada mewakili pohon dengan node, pointer kiri dan kanan, interval dll. Itu menghemat banyak memori dengan dasarnya tidak ada hit kinerja - Anda perlu melakukan aritmatika pointer sedikit lebih.
Poin kedua adalah bahwa, dengan biaya sedikit lebih banyak pekerjaan selama evaluasi, Anda dapat menggunakan pohon M-ary daripada pohon biner. Misalnya jika Anda menggunakan pohon 3-ary Anda akan menghitung maks 3 elemen sekaligus, lalu 9 elemen sekaligus, kemudian 27, dll. Penyimpanan tambahan yang diperlukan adalah N / (M-1) - Anda dapat buktikan menggunakan rumus deret geometri. Jika Anda memilih M = 11, misalnya, Anda akan membutuhkan 1/10 penyimpanan metode pohon biner.
Anda dapat memverifikasi bahwa implementasi naif dan dioptimalkan ini di Python memberikan hasil yang sama:
vs.
sumber
coba "segmen pohon" struktur data
ada 2 langkah
build_tree () O (n)
permintaan (int min, int max) O (nlogn)
http://en.wikipedia.org/wiki/Segment_tree
edit:
kalian tidak membaca wiki yang saya kirim!
algoritma ini adalah:
- Anda melintasi array 1 kali untuk membangun pohon. O (n)
- 10.000.000 berikutnya + kali Anda ingin tahu maks dari setiap bagian dari array, panggil saja fungsi permintaan. O (logn) untuk setiap kueri
- c ++ implementasikan di sini geeksforgeeks.org/segment-tree-set-1-range-minimum-query/
algoritma lama adalah:
setiap kueri, cukup lintasi area yang dipilih dan temukan.
jadi, jika Anda akan menggunakan algoritma ini untuk memproses sekali, OK, itu lebih lambat daripada cara lama. tetapi jika Anda akan memproses sejumlah besar query (miliar), itu sangat efisien Anda dapat menghasilkan file teks seperti ini, untuk uji
baris 1: 50.000 nomor acak 0-1.000.000, split oleh '(space)' (itu array)
baris 2: 2 angka acak dari 1 hingga 50.000, dibagi dengan '(spasi)' (ini permintaan)
...
baris 200000: suka baris 2, itu juga kueri acak
ini adalah contoh masalah, maaf tapi ini dalam bahasa Vietnam
http://vn.spoj.com/problems/NKLINEUP/
jika Anda menyelesaikannya dengan cara lama, Anda tidak akan pernah lulus.
sumber
O(n)
pencarian sederhana dari array, seperti yang dijelaskan dalam jawaban tarun_telang. Insting pertama adalah yangO(log n + k)
lebih cepat daripadaO(n)
, tetapiO(log n + k)
hanya pengambilan sub-array - setara denganO(1)
akses array mengingat titik awal dan akhir. Anda masih perlu melewatinya untuk menemukan yang maksimal.Anda dapat mencapai O (1) per kueri (dengan O (n log n) konstruksi) menggunakan struktur data yang disebut tabel jarang. Untuk setiap kekuatan 2 mari kita simpan maksimum untuk setiap segmen sepanjang ini. Sekarang diberikan segmen [l, r) Anda mendapatkan maksimum maksimum pada [l + 2 ^ k) dan [r-2 ^ k, r) untuk k yang sesuai. Mereka tumpang tindih tapi tidak apa-apa
sumber