Finden Sie die maximale Intervall Summe in einer Liste der reellen zahlen
Hier ist ein interview, das ein Kollege fragte nach einer Programmierung position. Ich dachte, das war toll für die Beobachtung der Gesprächspartner denken, es durch. Ich hätte gerne Antworten, wie die öffentlichkeit darüber denkt.
Gegeben eine Liste von reellen zahlen der Länge N, sagen [a_1, a_2, ..., a_N]
, was ist die Komplexität der Suche nach dem maximalen Wert M, für die es existieren Indizes 1 <= i <= j <= N, so dass
a_i + a_{i+1} + ... + a_j = M
?
Ich entschuldige mich, wenn dies ist ein klassisches CS-problem.
- Von welchem Typ sind die zahlen? Sie sagen ganzen zahlen im Titel, "reelle zahlen" in Frage. "Reelle zahlen" klingt wie negative und Fließkommazahlen erlaubt sind, "ganze zahlen" klingt ziemlich wie das Gegenteil.
- Danke für den Fang, die. In Wahrheit, es spielt keine Rolle, ob Sie ganze zahlen oder reelle zahlen, so lange Sie nicht Komplex sind und negative sind erlaubt.
- Ich war etwas zu warten, wie das EBEN so kann ich sagen: dies gehört zu den cstheory.stackexchange.com
- int vs real macht keinen Unterschied auf den Algorithmus
- Dies ist gemeinhin als "Maximum Subarray Problem"
- dies ist nicht Forschung-Ebene, so sollte es sein, auf math.Ob SE nicht SO.
- Werden Sie diese Frage in der Hoffnung auf eine Antwort? Oder einfach nur nach etwas, was interessant ist? Wenn letzteres, sollte dies wahrscheinlich ein community-wiki...
- es wohl gehört eigentlich der Stapel exchange-Standort für nicht-wissenschaftliche, mathematische Berechnungen, Programmierung-orientierte, interview-Fragen... jetzt nur, wenn ich mich erinnern konnte, den Namen der anderen Seite...
- Wenn nur gab es eine wheretoask.stackexchange.com wo Sie finden konnten, eine Antwort auf die Fragen der Natur.
- Round-off error.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Die Komplexität ist nur O(n) für die Kadane-Algorithmus:
Es ist
O(N)
:Der Idee zu halten, ist die Summe aller ganzen zahlen, die aufgetreten sind seit dem letzten zurücksetzen. Eine Rückstellung erfolgt, wenn die Summe geht unter null, d.h. es gibt zu viele negative zahlen im aktuellen Intervall zu machen, vielleicht die beste.
Dies ist eine klassische, bekannte, problem, dass ist ein hervorragender eye-opener in jeder Algorithmus natürlich. Es ist schwer zu finden, eine bessere/einfachere starter.
Finden Sie ein n*3-, n*2-, nlogn - und auch das einfache n-Algorithmus.
Fand ich das problem besprochen/gelöst John Bentleys "Programming Pearls" von 1986 -
und habe es seit Jahren als starter in unserem Algorithmus-Kurs an der NTNU/Trondheim.
Vor rund 20 Jahren habe ich zuerst verwendet es in einer Untersuchung für etwa 250 Schüler, wo nur 1 Schüler haben entdecken Sie alle 4 Lösungen, siehe oben. Er, Bjørn Olstad, wurde die "jüngste professor, der jemals" an der NTNU in Trondheim, und hat immer noch diesen status neben der überschrift der MSFT-Suche-division in Oslo.
Bjørn nahm auch die Herausforderung zu finden, gute praktische Anwendungen des Algorithmus. Sehen Sie einige?
Versuchen, diesen code .. es würde funktionieren für mindestens eine +ve-Zahl im array.. O(n) nur eine for-Schleife verwendet..
Könnte dies falsch sein, weil es verdächtig einfach.
Sieht es aus wie O(n).
Ich bin dringen auf diesen alten thread, um eine detaillierte Erklärung, warum der Kadane-Algorithmus funktioniert. Der Algorithmus wurde vorgestellt in einer Klasse, die ich derzeit nehmen, aber nur eine vage Erklärung. Hier ist eine Implementierung des Algorithmus in Haskell:
Nun, da wir versuchen nur zu verstehen, der Algorithmus, lassen Sie ' s rückgängig machen, die kleine Optimierung der Namensgebung
newSum
:Was ist diese verrückte Funktion
maxCont'
? Wir kommen mit einer einfachen Angabe, was es tun soll. Wir wollen die folgende zu halten, mit der Voraussetzung, dass0 ≤ thisSum ≤ maxSum
:wo
maxInit l
ist die größte Summe aus einem ersten segment vonl
undmaxCont
ist die maximale zusammenhängende Summe vonl
.Triviale, aber wichtige Tatsache: für alle
l
,maxInit l ≤ maxCont l
. Es sollte offensichtlich sein, dass die oben genannte Spezifikation garantiertmaxCont l = maxCont' 0 0 l
werden, was wir wollen. Anstatt zu versuchen, zu erklären, direkt, warum die Finale version von maxCont' implementiert die Spezifikation oben (die ich nicht wirklich wissen, wie zu tun), werde ich zeigen, wie es kann daraus abgeleitet werden, die Umwandlung der Spezifikation einen Schritt zu einer Zeit, bis es wird der code, der wird dann sicherlich richtig sein. Wie geschrieben, ist diese Angabe nicht geben-Implementierung: wennmaxCont
ist definiert in Bezug aufmaxCont'
wie oben beschrieben, wird die Schleife für immer alsmaxCont'
AnrufemaxCont
AnrufemaxCont'
mit der gleichen Liste. Also lassen Sie es erweitern sich nur ein bit zu setzen die Stücke, die wir benötigen:Diese nicht alles reparieren, aber es ausgesetzt Dinge. Lasst uns das nutzen.
thisSum + maxInit (x:xs)
ist entwederthisSum
oderthisSum + x + maxInit xs
. AberthisSum ≤ maxSum
mit der Voraussetzung, so können wir ignorieren diese Möglichkeit bei der Berechnung der maximalen.maxCont (x:xs)
ist eine Summe, die entwederx
oder nicht. Aber wenn es auchx
, dann ist es das gleiche wiemaxInit (x:xs)
unter der vorhergehenden, so können wir ignorieren diese Möglichkeit, nur den Fall betrachten, womaxCont (x:xs) = maxCont xs
. So kommen wir zu der nächsten version:Diese, schließlich, ist richtig, rekursiver, aber wir haben Möglichkeiten, um zu gehen, um zu effizienten code, vor allem, weil das mythische maxInit zu langsam wäre. Lassen Sie uns es brechen in den drei Fällen, als in den Java-code (Missbrauch von Haskell-notation ein bisschen):
Im ersten Fall wissen wir, dass
maxSum
können nicht das maximum:thisSum+x
ist größer undmaxInit xs
ist immer positiv. Im zweiten Fall wissen wir, dassthisSum+x+maxInit xs
können nicht das maximum:maxCont xs
ist immer mindestens so groß wiemaxInit xs
, undthisSum+x
negativ ist. So können wir vermeiden diesen Möglichkeiten:Nun haben wir gerade genug von einer Kante zu drehen die Dinge um. Jetzt haben wir beseitigt Fällen unmöglich, wir fügen Sie einige doppelte Fällen, die diese drei Fälle wieder in der gleichen form, so können wir Ersatz in der ursprünglichen Spezifikation von
maxCont'
. Im ersten Fall, wir haben nicht einen ersten Begriff, also brauchen wir etwas, das wir kennen, wird nicht mehr als die anderen Bedingungen. Zur Aufrechterhaltung der invariante, dassthisSum ≤ maxSum
wir brauchen, um denthisSum+x
. Im zweiten Fall haben wir nicht einen zweiten Begriff, der aussieht wiesomething+maxInit xs
, aber wir wissen, dassmaxInit xs ≤ maxCont xs
, so können wir sicher stick in0+maxInit xs
. Das hinzufügen dieser extra Bedingungen für die Regelmäßigkeit der Erträge die folgenden:Schließlich, nach der überprüfung der Voraussetzung, ersetzen wir in der Spezifikation,
bekommen
Fixieren diese in real-syntax und fügen die base weggelassen Fall ergibt sich der tatsächliche Algorithmus, das haben wir jetzt bewiesen, erfüllt die spec so lange, wie es endet. Aber jeder der aufeinander folgenden rekursiven Schritt arbeitet auf eine kürzere Liste, so tut es in der Tat kündigen.
Es gibt nur eine Letzte Sache zu tun, für meinen Willen, die zu schreiben, die letzten code mehr idiomatically und flexibel:
Ich habe versucht und getestet. Falls alle zahlen negativ sind, es gibt die größte negative Zahl.
Testfälle:
Code:
Ich würde eine Antwort, die enthält 2 Ansätze, das handle-array mit oder ohne positiven Elementen, geschrieben in
Java
.Code -
Java
MaxSubSum.java:
MaxSubSumTest.java:
(Test-Fall-über
TestNG
)Erklärung:
find()
Finden Sie max sub-array, nur sub-array mit positiver Summe.
Verhalten:
BTW:
findIncludeNonPositive()
Finden Sie max sub-array enthalten auch sub-array mit nicht-positiven Summe.
Verhalten:
BTW:
0
am Ende der sub-array, das ändert nichts an der Summe.Komplexität:
O(n)
O(1)