Gegeben zwei Arrays; $births
eine Liste der Geburtsjahre enthält , die anzeigen , wenn jemand geboren wurde, und $deaths
eine Liste der Tod Jahren enthält , die anzeigen , wenn jemand gestorben ist , wie können wir das Jahr , an dem die Bevölkerung am höchsten war finden?
Zum Beispiel bei folgenden Arrays:
$births = [1984, 1981, 1984, 1991, 1996];
$deaths = [1991, 1984];
Das Jahr, in dem die Bevölkerung am höchsten war, sollte sein 1996
, da die 3
Menschen in diesem Jahr am Leben waren, was die höchste Bevölkerungszahl aller Jahre war.
Hier ist die laufende Mathematik dazu:
| Geburt | Tod | Bevölkerung | | ------- | ------- | ------------ | | 1981 | | 1 | | 1984 | | 2 | | 1984 | 1984 | 2 | | 1991 | 1991 | 2 | | 1996 | | 3 |
Annahmen
Wir können mit Sicherheit davon ausgehen, dass das Jahr, in dem jemand geboren wird, um eins zunehmen kann und das Jahr, in dem jemand stirbt, um eins zunehmen kann. In diesem Beispiel wurden 1984 2 Personen geboren und 1 Person starb 1984, was bedeutet, dass die Bevölkerung in diesem Jahr um 1 zunahm.
Wir können auch davon ausgehen, dass die Anzahl der Todesfälle niemals die Anzahl der Geburten überschreiten wird und dass kein Tod eintreten kann, wenn die Bevölkerung bei 0 liegt.
Wir können auch davon ausgehen, dass die Jahre in beiden $deaths
und $births
niemals negative oder Gleitkommawerte sind ( sie sind immer positive ganze Zahlen größer als 0 ).
Wir können jedoch nicht davon ausgehen, dass die Arrays sortiert werden oder dass es keine doppelten Werte gibt.
Bedarf
Wir müssen eine Funktion schreiben, um das Jahr zurückzugeben, in dem die höchste Population aufgetreten ist, wenn diese beiden Arrays als Eingabe verwendet werden. Die Funktion kann zurückkehren 0
, false
, ""
, oder NULL
( jeder Wert akzeptabel Falsey ) , wenn die Eingabefelder leer sind oder wenn die Bevölkerung immer bei 0 gänzlich. Wenn die höchste Bevölkerung in mehreren Jahren aufgetreten ist, kann die Funktion das erste Jahr, in dem die höchste Bevölkerung erreicht wurde, oder ein nachfolgendes Jahr zurückgeben.
Zum Beispiel:
$births = [1997, 1997, 1997, 1998, 1999];
$deaths = [1998, 1999];
/* The highest population was 3 on 1997, 1998 and 1999, either answer is correct */
Darüber hinaus wäre es hilfreich , das Big O der Lösung einzubeziehen.
Mein bester Versuch, dies zu tun, wäre der folgende:
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;
}
Der obige Algorithmus sollte gegeben in Polynomzeit arbeiten ist es im schlimmsten Fall , O(((n log n) * 2) + k)
wo n
ist die Anzahl der Elemente von jedem Array sortiert werden und k
ist die Anzahl der Geburt Jahre ( da wissen wir, dass k
es immerk >= y
) , wo y
Zahl der Todes Jahre. Ich bin mir jedoch nicht sicher, ob es eine effizientere Lösung gibt.
Mein Interesse gilt lediglich einem verbesserten Big O der Rechenkomplexität gegenüber dem vorhandenen Algorithmus. Die Speicherkomplexität spielt keine Rolle. Auch die Laufzeitoptimierung ist nicht. Zumindest ist es kein Hauptanliegen . Kleinere / größere Laufzeitoptimierungen sind willkommen, aber hier nicht der Schlüsselfaktor.
quelle
Antworten:
Ich denke, wir können
O(n log n)
Zeit mitO(1)
zusätzlichem Speicherplatz haben, indem wir zuerst sortieren und dann eine aktuelle Population und ein globales Maximum beibehalten, während wir iterieren. Ich habe versucht, das aktuelle Jahr als Bezugspunkt zu verwenden, aber die Logik schien immer noch etwas schwierig zu sein, daher bin ich mir nicht sicher, ob sie vollständig funktioniert hat. Hoffentlich kann es eine Vorstellung von dem Ansatz geben.JavaScript-Code (Gegenbeispiele / Bugs willkommen)
Wenn der Jahresbereich
m
in der Größenordnung von liegtn
, können wir die Zählungen für jedes Jahr im Bereich speichern und habenO(n)
zeitliche Komplexität. Wenn wir Lust haben wollten, könnten wir auchO(n * log log m)
Zeitkomplexität haben, indem wir einen Y-schnellen Versuch verwenden , der eineO(log log m)
zeitliche Nachfolge-Suche ermöglicht.quelle
if(birth_i < death_j){//increment stuff + check max} else{//decrement}; birth_i||=infty; death_j||=infty
. Sie können auch bis zu iterierenmin(birthSize, deathSize)
. Wenn min die Geburt ist, hör auf. Wenn min der Tod ist (verdächtig ..), stoppen Sie und überprüfen Sie(max + birth.length-i)
Wir können dies in linearer Zeit mit Bucket Sort lösen. Angenommen, die Größe der Eingabe ist n und der Bereich der Jahre ist m.
Das größte kumulative Maximum ist Ihre Antwort.
Die Laufzeit beträgt O (n + m) und der zusätzlich benötigte Platz ist O (m).
Dies ist eine lineare Lösung in n, wenn m O (n) ist; dh wenn der Bereich der Jahre nicht schneller wächst als die Anzahl der Geburten und Todesfälle. Dies gilt mit ziemlicher Sicherheit für Daten aus der realen Welt.
quelle
O(n): Find the min and max year across births and deaths
2. Iterieren Sie erneut durch alle Geburten + Tod:O(n): Parse the births+death array, incrementing the appropriate index of the array
Dann tun Sie: O (m): Analysieren Sie Ihr Array und verfolgen Sie die kumulative Summe und ihren Maximalwert. (Sie müssen dieses Array nicht analysieren - Sie können MAX verfolgen, während Sie die Indizes in 2Fassen Sie zuerst die Geburten und Todesfälle in einer Karte zusammen (
year => population change
), sortieren Sie diese nach Schlüsseln und berechnen Sie die laufende Bevölkerung darüber.Dies sollte ungefähr sein
O(2n + n log n)
, won
ist die Anzahl der Geburten.quelle
ksort($indexed)
) irrelevant.$indexed = array_count_values($births);
.Ich habe dieses Problem mit einem Speicherbedarf von
O(n+m)
[im schlimmsten Fall im besten FallO(n)
] gelöst.und zeitliche Komplexität von
O(n logn)
.Hier
n & m
sind die Längebirths
unddeaths
Arrays.Ich kenne kein PHP oder Javascript. Ich habe es mit Java implementiert und die Logik ist sehr einfach. Aber ich glaube, meine Idee kann auch in diesen Sprachen umgesetzt werden.
Technische Details:
Ich habe Java-
TreeMap
Struktur verwendet, um Aufzeichnungen über Geburten und Todesfälle zu speichern.TreeMap
Fügt Daten sortiert ( schlüsselbasiert ) als (Schlüssel, Wert) Paar ein. Hier ist der Schlüssel das Jahr und der Wert die kumulierte Summe von Geburten und Todesfällen (negativ für Todesfälle).Wir müssen keinen Todeswert einfügen, der nach dem höchsten Geburtsjahr aufgetreten ist.
Sobald die TreeMap mit den Aufzeichnungen zu Geburten und Sterbefällen gefüllt ist, werden alle kumulierten Summen aktualisiert und die maximale Bevölkerungszahl mit fortschreitendem Jahr gespeichert.
Beispielein- und -ausgabe: 1
Beispielein- und -ausgabe: 2
Hier ereigneten sich Todesfälle (
1914 & later
) nach dem letzten Geburtsjahr1913
, wurden überhaupt nicht gezählt, was unnötige Berechnungen vermeidet.Für insgesamt
10 million
Daten (Geburten und Todesfälle zusammen) und darüber1000 years range
dauerte das Programm3 sec.
fast.Wenn Daten gleicher Größe mit
100 years range
, dauerte es1.3 sec
.Alle Eingaben werden zufällig getroffen.
quelle
Dies wird die Möglichkeit eines gebundenen Jahres berücksichtigen, sowie wenn ein Jahr des Todes einer Person nicht der Geburt einer Person entspricht.
quelle
In Bezug auf das Gedächtnis ist es zu behalten
currentPopulation
und zucurrentYear
berechnen. Das Sortieren von Arrays$births
und$deaths
Arrays ist ein sehr guter Punkt, da das Sortieren von Blasen keine so schwere Aufgabe ist und es dennoch ermöglicht, einige Ecken zu schneiden:Ich bin nicht wirklich daran interessiert, in das Big O- Ding einzutauchen, sondern habe es dir überlassen.
Wenn Sie
currentYearComputing
jede Schleife neu entdecken , können Sie Schleifen inif
Anweisungen ändern und mit nur einer Schleife verlassen.quelle
Ich fülle diese Lösung sehr bequem aus, die Komplexität Big O ist n + m
quelle
$tmpArray--
sein$tmpArray[$death]--
? Bitte auch testen mit$births=[1997,1997,1998]; $deaths=[];
- Kommt es so zurück,1998
wie es sollte?$births = [3,1,2,1,3,3,2]
und$deaths = [2,3,2,3,3,3]
ich würde erwarten, dass er2
als Jahr mit der höchsten Bevölkerungszahl zurückkommt, aber Ihr Code kehrt zurück1
. Tatsächlich hat Ihr Code 9 von 15 meiner Komponententests nicht bestanden . Ich kann dies nicht nur nicht als die effizienteste Antwort akzeptieren , sondern ich kann es auch nicht als effizienteste Antwort akzeptieren, da es überhaupt nicht funktioniert.Einer der einfachsten und klarsten Ansätze für Ihr Problem.
Ausgabe :
Komplexität :
quelle
29.64 milliseconds