Дано два массива; $births
содержащий список лет рождения, указывающих, когда кто-то родился, и $deaths
содержащий список лет смерти, указывающих, когда кто-то умер, как мы можем найти год, в котором население было самым высоким?
Например, приведены следующие массивы:
$births = [1984, 1981, 1984, 1991, 1996];
$deaths = [1991, 1984];
Год, в котором население было самым высоким, должен быть 1996
, потому что 3
люди были живы в течение этого года, который был самым высоким числом населения за все эти годы.
Вот бегущая математика по этому поводу:
| Рождение | Смерть | Население | ------- | ------- | ------------ | | 1981 | | 1 | | 1984 | | 2 | | 1984 | 1984 | 2 | | 1991 | 1991 | 2 | | 1996 | | 3 |
Предположения
Мы можем с уверенностью предположить, что год, в котором кто-то родился, население может увеличиться на один, и год, в котором кто-то умер, население может уменьшиться на один. Таким образом, в этом примере 2 человека родились в 1984 году, а 1 человек умер в 1984 году, то есть население увеличилось на 1 за этот год.
Мы также можем с уверенностью предположить, что число смертей никогда не будет превышать число рождений и что никакой смерти не может произойти, когда население составляет 0.
Мы также можем с уверенностью предположить, что годы в обоих $deaths
и $births
никогда не будут отрицательными значениями или значениями с плавающей запятой ( они всегда являются положительными целыми числами больше 0 ).
Однако мы не можем предполагать, что массивы будут отсортированы или что не будет повторяющихся значений.
Требования
Мы должны написать функцию, которая будет возвращать год, в который произошло наибольшее население, учитывая эти два массива в качестве входных данных. Функция может возвращать 0
, false
, ""
или NULL
( любое значение falsey приемлемо ) , если входные массивы являются пустыми или если население всегда было на 0 в течение. Если наибольшая численность населения наблюдалась в течение нескольких лет, функция может возвращать первый год, в который была достигнута наибольшая численность населения, или любой последующий год.
Например:
$births = [1997, 1997, 1997, 1998, 1999];
$deaths = [1998, 1999];
/* The highest population was 3 on 1997, 1998 and 1999, either answer is correct */
Кроме того, было бы полезно включить Big O решения.
Моя лучшая попытка сделать это была бы следующей:
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;
}
Вышеприведенный алгоритм должен работать за полиномиальное время, учитывая, что в худшем O(((n log n) * 2) + k)
случае n
это число элементов, которые должны быть отсортированы из каждого массива, и k
число лет рождения ( поскольку мы знаем, что k
это всегдаk >= y
), где y
число лет смерти. Однако я не уверен, есть ли более эффективное решение.
Мои интересы просто в улучшенном Big O вычислительной сложности по существующему алгоритму. Сложность памяти не имеет значения. Также не оптимизация во время выполнения. По крайней мере, это не главное . Любые второстепенные / существенные оптимизации времени исполнения приветствуются, но это не ключевой фактор.
Ответы:
Я думаю, что у нас может быть
O(n log n)
время сO(1)
дополнительным пространством, сначала отсортировав, а затем сохранив текущую совокупность и глобальный максимум во время итерации. Я пытался использовать текущий год в качестве ориентира, но логика все еще казалась немного хитрой, поэтому я не уверен, что она полностью проработана. Надеюсь, это может дать представление о подходе.Код JavaScript (контрпримеры / ошибки приветствуются)
Если диапазон по годам
m
порядкаn
, мы могли бы хранить значения для каждого года в диапазоне и иметьO(n)
временную сложность. Если бы мы хотели получить фантазию, мы могли бы также иметьO(n * log log m)
временную сложность, используя Y-быстрый метод, который позволяет искать преемника воO(log log m)
времени.источник
if(birth_i < death_j){//increment stuff + check max} else{//decrement}; birth_i||=infty; death_j||=infty
, Также вы можете перебирать доmin(birthSize, deathSize)
. если мин это рождение, остановись. если мин - смерть (подозрительно ..), остановись и проверь(max + birth.length-i)
Мы можем решить это за линейное время с сортировкой сегментов. Допустим, размер ввода равен n, а диапазон лет равен m.
Самый большой совокупный максимум - ваш ответ.
Время работы составляет O (n + m), а необходимое дополнительное пространство - O (m).
Это линейное решение по n, если m равно O (n); то есть, если диапазон лет не растет быстрее, чем число рождений и смертей. Это почти наверняка верно для данных реального мира.
источник
O(n): Find the min and max year across births and deaths
2. повторить еще раз для всех рождений + смерти:O(n): Parse the births+death array, incrementing the appropriate index of the array
затем вы выполните: O (m): проанализируйте ваш массив, отслеживая совокупную сумму и ее максимальное значение. (вам не нужно анализировать этот массив - вы можете отслеживать MAX при увеличении индексов в 2)Сначала объедините рождения и смерти в карту (
year => population change
), отсортируйте их по ключам и рассчитайте численность населения по ним.Это должно быть приблизительно
O(2n + n log n)
, гдеn
число рождений.источник
ksort($indexed)
) становится неактуальной.$indexed = array_count_values($births);
.Я решил эту проблему с требованием памяти
O(n+m)
[в худшем случае, в лучшем случаеO(n)
]и, время сложность
O(n logn)
.Здесь
n & m
указаны длиныbirths
иdeaths
массивы.Я не знаю PHP или JavaScript. Я реализовал это с помощью Java, и логика очень проста. Но я верю, что моя идея может быть реализована и на этих языках.
Детали техники:
Я использовал
TreeMap
структуру Java для хранения записей о рождении и смерти.TreeMap
вставляет отсортированные данные (на основе ключа) в виде пары (ключ, значение), здесь ключ - это год, а значение - совокупная сумма рождений и смертей (отрицательная для смертей).Нам не нужно вводить значение смертности, которое произошло после самого высокого года рождения.
После того как TreeMap заполнен записями о рождении и смерти, все совокупные суммы обновляются и сохраняют максимальную численность населения за год по мере ее развития.
Пример ввода и вывода: 1
Пример ввода и вывода: 2
Здесь случаи смерти (
1914 & later
) после последнего года рождения1913
вообще не учитывались, что позволяет избежать ненужных вычислений.По общей сумме
10 million
данных (количество рождений и смертей) и более1000 years range
, программа3 sec.
завершилась.Если данные того же размера
100 years range
, это заняло1.3 sec
.Все входы выбираются случайным образом.
источник
Это будет учитывать возможность связанного года, а также, если год чьей-либо смерти не соответствует чьему-либо рождению.
источник
Память целесообразно сохранить
currentPopulation
иcurrentYear
просчитать. Начать с сортировки$births
и$deaths
массивов - очень хороший момент, потому что пузырьковая сортировка не такая уж тяжелая задача, но позволяет срезать некоторые углы:не очень-то увлеченный погружением в Big O , оставь это тебе.
Кроме того, если вы заново открываете
currentYearComputing
каждый цикл, вы можете изменить циклы наif
операторы и оставить только один цикл.источник
Я заполняю очень удобно это решение, сложность Big O составляет n + m
источник
$tmpArray--
быть$tmpArray[$death]--
? Также, пожалуйста, проверьте с$births=[1997,1997,1998]; $deaths=[];
- он возвращается1998
как следует?$births = [3,1,2,1,3,3,2]
и$deaths = [2,3,2,3,3,3]
я ожидаю, что вернусь2
как год с наибольшим населением, но ваш код вернется1
. На самом деле ваш код не прошел 9 из 15 моих модульных тестов . Я не только не могу принять это как самый эффективный ответ, но я даже не могу принять это как эффективный ответ, так как он не работает вообще.Один из самых простых и понятных подходов к вашей проблеме.
вывод :
сложность :
источник
29.64 milliseconds