Diberikan dua array; $births
berisi daftar tahun kelahiran yang menunjukkan kapan seseorang dilahirkan, dan $deaths
berisi daftar tahun kematian yang menunjukkan kapan seseorang meninggal, bagaimana kita dapat menemukan tahun di mana populasi tertinggi?
Misalnya diberikan array berikut:
$births = [1984, 1981, 1984, 1991, 1996];
$deaths = [1991, 1984];
Tahun di mana populasi tertinggi seharusnya 1996
, karena 3
orang-orang hidup selama tahun itu, yang merupakan jumlah populasi tertinggi sepanjang tahun itu.
Inilah perhitungannya:
| Kelahiran | Kematian | Populasi | | ------- | ------- | ------------ | | 1981 | | 1 | | 1984 | | 2 | | 1984 | 1984 | 2 | | 1991 | 1991 | 2 | | 1996 | | 3 |
Asumsi
Kita dapat dengan aman berasumsi bahwa tahun di mana seseorang dilahirkan populasi dapat meningkat satu dan tahun di mana seseorang meninggal populasi dapat berkurang satu. Jadi, dalam contoh ini, 2 orang lahir pada tahun 1984 dan 1 orang meninggal pada tahun 1984, artinya populasi meningkat 1 pada tahun itu.
Kita juga dapat dengan aman berasumsi bahwa jumlah kematian tidak akan pernah melebihi jumlah kelahiran dan bahwa tidak ada kematian dapat terjadi ketika populasi berada pada 0.
Kita juga dapat dengan aman mengasumsikan bahwa tahun-tahun di keduanya $deaths
dan $births
tidak akan pernah menjadi nilai negatif atau floating point ( mereka selalu bilangan bulat positif lebih besar dari 0 ).
Kami tidak dapat berasumsi bahwa array akan diurutkan atau tidak akan ada nilai duplikat.
Persyaratan
Kita harus menulis fungsi untuk mengembalikan tahun di mana populasi tertinggi terjadi, mengingat dua array ini sebagai input. Fungsi dapat kembali 0
, false
, ""
, atau NULL
( nilai apapun falsey diterima ) jika array masukan kosong atau jika populasi selalu pada 0 seluruh. Jika populasi tertinggi terjadi pada beberapa tahun, fungsi dapat mengembalikan tahun pertama di mana populasi tertinggi dicapai atau tahun berikutnya.
Sebagai contoh:
$births = [1997, 1997, 1997, 1998, 1999];
$deaths = [1998, 1999];
/* The highest population was 3 on 1997, 1998 and 1999, either answer is correct */
Selain itu, termasuk Big O dari solusi akan sangat membantu.
Upaya terbaik saya untuk melakukan ini adalah sebagai berikut:
function highestPopulationYear(Array $births, Array $deaths): Int {
sort($births);
sort($deaths);
$nextBirthYear = reset($births);
$nextDeathYear = reset($deaths);
$years = [];
if ($nextBirthYear) {
$years[] = $nextBirthYear;
}
if ($nextDeathYear) {
$years[] = $nextDeathYear;
}
if ($years) {
$currentYear = max(0, ...$years);
} else {
$currentYear = 0;
}
$maxYear = $maxPopulation = $currentPopulation = 0;
while(current($births) !== false || current($deaths) !== false || $years) {
while($currentYear === $nextBirthYear) {
$currentPopulation++;
$nextBirthYear = next($births);
}
while($currentYear === $nextDeathYear) {
$currentPopulation--;
$nextDeathYear = next($deaths);
}
if ($currentPopulation >= $maxPopulation) {
$maxPopulation = $currentPopulation;
$maxYear = $currentYear;
}
$years = [];
if ($nextBirthYear) {
$years[] = $nextBirthYear;
}
if ($nextDeathYear) {
$years[] = $nextDeathYear;
}
if ($years) {
$currentYear = min($years);
} else {
$currentYear = 0;
}
}
return $maxYear;
}
Algoritma di atas harus bekerja dalam waktu polinomial mengingat paling buruk di O(((n log n) * 2) + k)
mana n
jumlah elemen yang akan diurutkan dari setiap array dan k
jumlah tahun kelahiran ( karena kita tahu itu k
selaluk >= y
) di mana y
jumlah tahun kematian. Namun, saya tidak yakin apakah ada solusi yang lebih efisien.
Minat saya murni pada perbaikan kompleksitas komputasi pada algoritma yang ada. Kompleksitas memori tidak menjadi masalah. Optimasi runtime juga tidak. Setidaknya itu bukan masalah utama . Semua optimasi runtime minor / utama disambut baik, tetapi bukan faktor kunci di sini.
sumber
Jawaban:
Saya pikir kita dapat memiliki
O(n log n)
waktu denganO(1)
ruang tambahan dengan menyortir terlebih dahulu, kemudian mempertahankan populasi saat ini dan maksimum global seperti yang kita lakukan. Saya mencoba menggunakan tahun ini sebagai titik referensi tetapi logikanya masih tampak sedikit rumit jadi saya tidak yakin itu benar-benar berhasil. Semoga bisa memberi gambaran tentang pendekatannya.Kode JavaScript (welcome counterexamples / bug)
Jika rentang tahun
m
,, berada di urutann
, kita dapat menyimpan jumlah untuk setiap tahun dalam rentang dan memilikiO(n)
kompleksitas waktu. Jika kita ingin mendapatkan kemewahan, kita juga bisa memilikiO(n * log log m)
kompleksitas waktu, dengan menggunakan trie Y-fast yang memungkinkan pencarian pengganti dalamO(log log m)
waktu.sumber
if(birth_i < death_j){//increment stuff + check max} else{//decrement}; birth_i||=infty; death_j||=infty
. Anda juga dapat mengulangi hinggamin(birthSize, deathSize)
. jika min lahir, hentikan. jika min adalah kematian (curiga ..), berhenti dan periksa(max + birth.length-i)
Kita dapat menyelesaikan ini dalam waktu linier dengan semacam ember. Katakanlah ukuran input adalah n, dan rentang tahun adalah m.
Maksimum kumulatif terbesar adalah jawaban Anda.
Waktu berjalan adalah O (n + m), dan ruang tambahan yang dibutuhkan adalah O (m).
Ini adalah solusi linier dalam n jika m adalah O (n); yaitu, jika rentang tahun tidak tumbuh lebih cepat daripada jumlah kelahiran dan kematian. Ini hampir pasti benar untuk data dunia nyata.
sumber
O(n): Find the min and max year across births and deaths
2. iterate lagi melalui semua kelahiran + kematian:O(n): Parse the births+death array, incrementing the appropriate index of the array
maka Anda lakukan: O (m): Parsing array Anda, catat jumlah kumulatif dan nilai maksimumnya. (Anda tidak perlu menguraikan array ini - Anda dapat melacak MAX sambil meningkatkan indeks dalam 2)Pertama agregat kelahiran dan kematian ke dalam peta (
year => population change
), urutkan berdasarkan kunci, dan hitung populasi yang berjalan di atasnya.Ini harus kira-kira
O(2n + n log n)
, di manan
jumlah kelahiran.sumber
ksort($indexed)
) menjadi tidak relevan.$indexed = array_count_values($births);
.Saya memecahkan masalah ini dengan persyaratan memori
O(n+m)
[dalam kasus terburuk, kasus terbaikO(n)
]dan, kompleksitas waktu
O(n logn)
.Di sini,
n & m
adalah panjangbirths
dandeaths
array.Saya tidak tahu PHP atau javascript. Saya sudah mengimplementasikannya dengan Java dan logikanya sangat sederhana. Tapi saya percaya ide saya dapat diimplementasikan dalam bahasa-bahasa itu juga
Detail Teknik:
Saya menggunakan
TreeMap
struktur java untuk menyimpan catatan kelahiran dan kematian.TreeMap
memasukkan data yang diurutkan ( berbasis kunci ) sebagai pasangan (kunci, nilai), di sini kunci adalah tahun dan nilainya adalah jumlah kumulatif dari kelahiran & kematian (negatif untuk kematian).Kita tidak perlu memasukkan nilai kematian yang terjadi setelah tahun kelahiran tertinggi .
Setelah TreeMap diisi dengan catatan kelahiran & kematian, semua jumlah kumulatif diperbarui dan menyimpan populasi maksimum dengan tahun seiring kemajuan.
Contoh input & output: 1
Contoh input & output: 2
Di sini, kematian terjadi (
1914 & later
) setelah tahun kelahiran terakhir1913
, tidak dihitung sama sekali, yang menghindari perhitungan yang tidak perlu.Untuk total
10 million
data (kombinasi kelahiran & kematian) dan yang lebih1000 years range
, program ini akan3 sec.
selesai.Jika ukuran data sama dengan
100 years range
, butuh1.3 sec
.Semua input diambil secara acak.
sumber
Ini akan menjelaskan kemungkinan tahun terikat, serta jika satu tahun kematian seseorang tidak sesuai dengan kelahiran seseorang.
sumber
Memori bijaksana untuk menjaga
currentPopulation
dancurrentYear
menghitung. Memulai dengan menyortir keduanya$births
dan$deaths
array adalah hal yang sangat baik, karena bubble sorting bukanlah tugas yang berat, namun memungkinkan untuk memotong beberapa sudut:tidak benar-benar tertarik untuk menyelam ke hal Big O , serahkan pada Anda.
Juga, jika Anda menemukan kembali
currentYearComputing
setiap loop, Anda dapat mengubah loop menjadiif
pernyataan dan pergi hanya dengan satu loop.sumber
Saya mengisi solusi ini sangat nyaman, kompleksitas Big O adalah n + m
sumber
$tmpArray--
seharusnya$tmpArray[$death]--
? Tolong juga tes dengan$births=[1997,1997,1998]; $deaths=[];
- Apakah kembali1998
seperti seharusnya?$births = [3,1,2,1,3,3,2]
dan$deaths = [2,3,2,3,3,3]
saya berharap untuk kembali2
sebagai tahun populasi tertinggi, namun kode Anda kembali1
. Sebenarnya kode Anda gagal 9 dari 15 tes unit saya . Saya tidak hanya tidak dapat menerima ini sebagai jawaban yang paling efisien, tetapi saya bahkan tidak bisa menerimanya sebagai jawaban yang efisien karena tidak berfungsi sama sekali.Salah satu pendekatan paling sederhana dan jelas untuk masalah Anda.
keluaran :
kompleksitas :
sumber
29.64 milliseconds