Wenn Sie hier sind, besteht die Möglichkeit, dass Sie versucht haben, das „maximale Subarray-Problem“ zu lösen, und auf Kadanes Algorithmus gestoßen sind, aber nicht herausfinden konnten, wie so etwas funktioniert. Oder vielleicht waren Sie es leid, Kadanes Algorithmus als „Blackbox“zu verwenden. Oder vielleicht wollten Sie den dynamischen Programmieraspekt verstehen. Oder vielleicht möchten Sie nur etwas über ein neues Konzept lernen, das Sie beim Programmieren besser machen kann. Was auch immer der Grund sein mag, du bist an der richtigen Stelle.,

Um Kadanes Algorithmus besser zu verstehen, würden wir zunächst eine kurze Einführung in die dynamische Programmierung geben. Dann würden wir uns ein ziemlich beliebtes Programmierproblem ansehen, das maximale Subarray-Problem. Wir würden sehen, wie dieses Problem mit einem Brute-Force-Ansatz gelöst werden kann, und dann würden wir versuchen, unseren Ansatz zu verbessern und einen besseren Algorithmus zu entwickeln, auch bekannt als Kadanes Algorithmus.

Also, lass uns darauf eingehen.,

Dynamische Programmierung

Dynamische Programmierung ist eine Methode zur Lösung eines komplexen Problems, indem es in eine Sammlung einfacherer Unterprobleme zerlegt, jedes dieser Unterprobleme nur einmal gelöst und gespeichert wird ihre Lösungen mit einer speicherbasierten Datenstruktur (Array, Map usw.).). Wenn also das nächste Mal dasselbe Teilproblem auftritt, anstatt seine Lösung neu zu berechnen, sucht man einfach nach der zuvor berechneten Lösung, wodurch Rechenzeit gespart wird.

Diejenigen, die sich nicht an die Vergangenheit erinnern können, sind dazu verdammt, sie zu wiederholen., – Dynamische Programmierung

Hier ist eine brillante Erklärung zum Konzept der dynamischen Programmierung auf Quora — Jonathan Paulsons Antwort auf Wie soll ich einem 4-Jährigen dynamische Programmierung erklären?

Obwohl es mehr zu dynamischer Programmierung gibt, würden wir vorwärts gehen, um das maximale Subarray-Problem zu verstehen.

Maximales Subarray-Problem

Das maximale Subarray-Problem besteht darin, die größtmögliche Summe eines zusammenhängenden Subarrays innerhalb eines gegebenen eindimensionalen Arrays A von Zahlen zu finden.,

Maximale Summe Subarray (In Gelb)

Für das oben angegebene Array ist beispielsweise das zusammenhängende Subarray mit der größten Summe mit der Summe 6. Wir würden dieses Array als Beispiel für den Rest dieses Artikels verwenden. Außerdem würden wir davon ausgehen, dass dieses Array null-indiziert ist, dh -2 würde als ‚0.‘ Element des Arrays und so weiter aufgerufen werden. Außerdem würde A den Wert bei Index i darstellen.,

Nun würden wir uns eine sehr offensichtliche Lösung für das gegebene Problem ansehen.

Brute-Force-Ansatz

Eine sehr offensichtliche, aber nicht so gute Lösung besteht darin, die Summe jedes möglichen Subarrays zu berechnen, und das Maximum davon wäre die Lösung. Wir können mit Index 0 beginnen und die Summe jedes möglichen Subarrays berechnen, beginnend mit dem Element A, wie in der folgenden Abbildung gezeigt. Dann würden wir die Summe jedes möglichen Subarrays berechnen, beginnend mit A, A usw. bis zu A, wobei n die Größe des Arrays bezeichnet (in unserem Fall n = 9)., Beachten Sie, dass jedes einzelne Element selbst ein Subarray ist.

Brute-Force-Ansatz: Iteration 0 (links) und Iteration 1 (rechts)

Wir rufen die maximale Summe von Subarrays auf, beginnend mit Element A, dem local_maximum bei Index i. Nachdem wir alle Indizes durchlaufen haben, bleibt local_maximum für alle Indizes. Schließlich können wir das Maximum dieser local_maximums finden und wir würden die endgültige Lösung erhalten, dh, die maximal mögliche Summe. Wir würden dies global_maximum nennen.

Möglicherweise stellen Sie jedoch fest, dass dies keine sehr gute Methode ist, da mit zunehmender Größe des Arrays die Anzahl der möglichen Subarrays schnell zunimmt und somit die Rechenkomplexität zunimmt. Oder genauer gesagt, wenn die Größe des Arrays n ist, dann ist die Zeitkomplexität dieser Lösung O(n2), was nicht sehr gut ist.

Wie können wir das verbessern? Gibt es eine Möglichkeit, das Konzept der dynamischen Programmierung zu verwenden? Lass es uns herausfinden.,

Kadanes Algorithmus

In diesem Abschnitt würden wir den oben diskutierten Brute-Force-Ansatz erneut verwenden, aber diesmal würden wir rückwärts beginnen. Wie würde das helfen? Mal sehen.

Wir würden vom letzten Element ausgehen und die Summe jedes möglichen Subarrays berechnen, das mit dem Element A endet, wie in der folgenden Abbildung gezeigt. Dann würden wir die Summe jedes möglichen Subarrays berechnen, das mit A, A usw. endet, bis zu A.,

Rückwärts Brute-Force-Ansatz: Iteration 0 (links) und Iteration 1 (rechts)

Konzentrieren wir uns nun auf die Subarrays, die mit dem Element A (=-1) und A (=2) enden, wie in der folgenden Abbildung gezeigt.,

Aus der obigen Abbildung sehen wir, dass das local_maximum gleich 3 ist, was die Summe von das Subarray . Schauen Sie sich nun die Subarrays an, die mit A. Sie werden feststellen, dass diese Subarrays in zwei Teile unterteilt werden können, die Subarrays, die mit A (gelb hervorgehoben) und dem Einzelelement-Subarray A (grün) enden.

Nehmen wir an, ich kenne irgendwie das local_maximum., Dann sehen wir, dass wir zur Berechnung des local_maximums nicht die Summe aller mit A endenden Subarrays berechnen müssen, da wir das Ergebnis bereits aus Arrays kennen, die mit A enden.Beachten Sie, dass, wenn array die maximale Summe hätte, wir nur die mit den roten Pfeilen hervorgehobenen Arrays überprüfen müssen, um local_maximum zu berechnen. Und das führt uns zu dem Prinzip, nach dem Kadanes Algorithmus arbeitet.

local_maximum bei Index i ist das Maximum von A und die Summe von A und local_maximum bei Index i-1.,

Mit der obigen Methode müssen wir das Array nur einmal durchlaufen, was viel besser ist als unser früherer Brute-Force-Ansatz. Oder genauer gesagt, die Zeitkomplexität von Kadanes Algorithmus ist O (n).

Schließlich wollen wir sehen, wie das alles im Code funktionieren würde.,

Code Walkthrough

Unten ist eine sehr selbsterklärende Implementierung (in C++) einer Funktion, die ein Array als Argument verwendet und die Summe des maximalen Subarrays zurückgibt.

Beachten Sie, dass wir anstelle eines Arrays zum Speichern von local_maximums einfach die neuesten local_maximum in einer int-Typvariablen ‚local_max‘, da wir das nächste local_maximum berechnen müssen., Außerdem verwenden wir eine Variable ‚global_max‘, um den Maximalwert von local_maximum zu verfolgen, der sich am Ende als erforderliche Ausgabe herausstellt.

Schlussfolgerung

Aufgrund der Art und Weise, wie dieser Algorithmus optimale Unterstrukturen verwendet (das maximale Subarray, das an jeder Position endet, wird auf einfache Weise aus einem verwandten, aber kleineren und überlappenden Subproblem berechnet: das maximale Subarray, das an der vorherigen Position endet) kann dieser Algorithmus als einfaches Beispiel für dynamische Programmierung angesehen werden., Kadanes Algorithmus ist in der Lage, die maximale Summe eines zusammenhängenden Subarrays in einem Array mit einer Laufzeit von O(n) zu finden.

Articles

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.