Étant donné deux tableaux; $births
contenant une liste des années de naissance indiquant quand quelqu'un est né, et $deaths
contenant une liste des années de décès indiquant quand quelqu'un est décédé, comment pouvons-nous trouver l'année où la population était la plus élevée?
Par exemple, étant donné les tableaux suivants:
$births = [1984, 1981, 1984, 1991, 1996];
$deaths = [1991, 1984];
L'année où la population était la plus élevée devrait être 1996
, car les 3
gens étaient en vie au cours de cette année, qui était le nombre de personnes le plus élevé de toutes ces années.
Voici les calculs en cours à ce sujet:
| Naissance | La mort | Population | | ------- | ------- | ------------ | | 1981 | | 1 | | 1984 | | 2 | | 1984 | 1984 | 2 | | 1991 | 1991 | 2 | | 1996 | | 3 |
Hypothèses
Nous pouvons supposer avec certitude que l'année de naissance d'une personne, la population peut augmenter d'une unité et l'année de décès d'une personne, la population peut diminuer d'une unité. Ainsi, dans cet exemple, 2 personnes sont nées en 1984 et 1 personne est décédée en 1984, ce qui signifie que la population a augmenté de 1 cette année-là.
Nous pouvons également supposer en toute sécurité que le nombre de décès ne dépassera jamais le nombre de naissances et qu'aucun décès ne peut survenir lorsque la population est à 0.
Nous pouvons également supposer en toute sécurité que les années dans les deux $deaths
et $births
ne seront jamais des valeurs négatives ou à virgule flottante ( ce sont toujours des entiers positifs supérieurs à 0 ).
Nous ne pouvons cependant pas supposer que les tableaux seront triés ou qu'il n'y aura pas de valeurs en double, cependant.
Exigences
Nous devons écrire une fonction pour retourner l'année où la population la plus élevée s'est produite, étant donné ces deux tableaux en entrée. La fonction peut retourner 0
, false
, ""
, ou NULL
( toute valeur de Falsey est acceptable ) si les tableaux d'entrée sont vides ou si la population était toujours à 0 ° C tout au long. Si la population la plus élevée s'est produite sur plusieurs années, la fonction peut renvoyer la première année au cours de laquelle la population la plus élevée a été atteinte ou toute année suivante.
Par exemple:
$births = [1997, 1997, 1997, 1998, 1999];
$deaths = [1998, 1999];
/* The highest population was 3 on 1997, 1998 and 1999, either answer is correct */
De plus, l'inclusion du Big O de la solution serait utile.
Ma meilleure tentative pour ce faire serait la suivante:
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;
}
L'algorithme ci-dessus devrait fonctionner en temps polynomial étant donné qu'il est au pire O(((n log n) * 2) + k)
où n
est le nombre d'éléments à trier de chaque tableau et k
est le nombre d'années de naissance ( car nous savons que k
c'est toujoursk >= y
) où y
est le nombre d'années de décès. Cependant, je ne sais pas s'il existe une solution plus efficace.
Mes intérêts sont purement dans un Big O amélioré de complexité de calcul sur l'algorithme existant. La complexité de la mémoire n'est pas un problème. L'optimisation de l'exécution n'est pas non plus. Au moins, ce n'est pas une préoccupation principale . Toutes les optimisations d'exécution mineures / majeures sont les bienvenues, mais pas le facteur clé ici.
la source
Réponses:
Je pense que nous pouvons avoir du
O(n log n)
temps avec de l'O(1)
espace supplémentaire en triant d'abord, puis en maintenant une population actuelle et un maximum global pendant que nous itérons. J'ai essayé d'utiliser l'année en cours comme point de référence, mais la logique semblait encore un peu délicate, donc je ne suis pas sûr qu'elle soit complètement réglée. Espérons que cela puisse donner une idée de l'approche.Code JavaScript (contre-exemples / bugs bienvenus)
Si la plage des années,,
m
est de l'ordre den
, nous pourrions stocker les chiffres pour chaque année dans la plage et avoir uneO(n)
complexité temporelle. Si nous voulions devenir fantaisistes, nous pourrions également avoir uneO(n * log log m)
complexité temporelle, en utilisant un tri rapide Y qui permet une recherche successive dans leO(log log m)
temps.la source
if(birth_i < death_j){//increment stuff + check max} else{//decrement}; birth_i||=infty; death_j||=infty
. Vous pouvez également parcourir jusqu'àmin(birthSize, deathSize)
. si min est la naissance, arrêtez. si min est mort (suspect ..), arrêtez et vérifiez(max + birth.length-i)
Nous pouvons résoudre ce problème en temps linéaire avec le tri par compartiment. Disons que la taille de l'entrée est n et que la plage d'années est m.
Le maximum cumulatif le plus élevé est votre réponse.
Le temps de fonctionnement est O (n + m) et l'espace supplémentaire nécessaire est O (m).
Il s'agit d'une solution linéaire dans n si m est O (n); c'est-à-dire, si le nombre d'années ne croît pas plus rapidement que le nombre de naissances et de décès. Cela est presque certainement vrai pour les données du monde réel.
la source
O(n): Find the min and max year across births and deaths
2. itérer à nouveau à travers toutes les naissances + décès:O(n): Parse the births+death array, incrementing the appropriate index of the array
alors vous faites: O (m): Analysez votre tableau, en gardant une trace de la somme cumulée et de sa valeur maximale. (vous n'avez pas besoin d'analyser ce tableau - vous pouvez garder une trace de MAX tout en incrémentant les indices en 2)Commencez par regrouper les naissances et les décès sur une carte (
year => population change
), triez-les par clé et calculez la population en cours d'exécution.Cela devrait être approximativement
O(2n + n log n)
, oùn
est le nombre de naissances.la source
ksort($indexed)
) devient inutile.$indexed = array_count_values($births);
.J'ai résolu ce problème avec une mémoire requise
O(n+m)
[dans le pire des cas, dans le meilleur des casO(n)
]et la complexité temporelle de
O(n logn)
.Voici
n & m
la longueurbirths
et lesdeaths
tableaux.Je ne connais pas PHP ou javascript. Je l'ai implémenté avec Java et la logique est très simple. Mais je crois que mon idée peut également être implémentée dans ces langues.
Détails techniques:
J'ai utilisé la
TreeMap
structure java pour stocker les enregistrements de naissances et de décès.TreeMap
insère des données triées ( basées sur les clés ) sous forme de paire (clé, valeur), ici la clé est l'année et la valeur est la somme cumulée des naissances et des décès (négatif pour les décès).Nous n'avons pas besoin d'insérer la valeur des décès survenus après l' année de naissance la plus élevée .
Une fois que TreeMap est rempli avec les enregistrements de naissances et de décès, toutes les sommes cumulées sont mises à jour et stockent la population maximale avec l'année au fur et à mesure de sa progression.
Exemple d'entrée et de sortie: 1
Exemple d'entrée et de sortie: 2
Ici, les décès survenus (
1914 & later
) après la dernière année de naissance1913
, n'ont pas été comptés du tout, ce qui évite les calculs inutiles.Pour un total de
10 million
données (naissances et décès combinés) et plus1000 years range
, le programme a pris sur le point3 sec.
de se terminer.Si des données de même taille avec
100 years range
, il a fallu1.3 sec
.Toutes les entrées sont prises au hasard.
la source
Cela tiendra compte de la possibilité d'une année liée, ainsi que si une année de décès d'une personne ne correspond pas à la naissance d'une personne.
la source
En termes de mémoire, il est à conserver
currentPopulation
et àcurrentYear
calculer. Commencer par trier les deux$births
et les$deaths
tableaux est un très bon point, car le tri à bulles n'est pas une tâche si lourde, mais permet de couper certains coins:pas vraiment envie de plonger dans Big O , laissez-le vous.
De plus, si vous redécouvrez
currentYearComputing
chaque boucle, vous pouvez changer les boucles enif
instructions et partir avec une seule boucle.la source
Je remplis très à l'aise cette solution, la complexité Big O est n + m
la source
$tmpArray--
être$tmpArray[$death]--
? Veuillez également tester avec$births=[1997,1997,1998]; $deaths=[];
- Retourne-t-il1998
comme il se doit?$births = [3,1,2,1,3,3,2]
et$deaths = [2,3,2,3,3,3]
je m'attendrais à revenir en2
tant qu'année de population la plus élevée, mais votre code revient1
. En fait, votre code a échoué 9 sur 15 de mes tests unitaires . Non seulement je ne peux pas accepter cela comme la réponse la plus efficace, mais je ne peux même pas l'accepter comme une réponse efficace car cela ne fonctionne pas du tout.L'une des approches les plus simples et les plus claires pour votre problème.
sortie :
complexité :
la source
29.64 milliseconds