Gibt es einen anderen effizienten Algorithmus als die Brute-Force-Suche, um die drei ganzen Zahlen zu finden?
Ja; wir können dies in O (n 2 ) Zeit lösen ! Bedenken Sie zunächst, dass Ihr Problem Pauf eine etwas andere Weise äquivalent formuliert werden kann, sodass kein "Zielwert" erforderlich ist:
ursprüngliches Problem P: Gibt es bei einem Array Avon nganzen Zahlen und einem Zielwert Sein 3-Tupel von Adiesen Summen bis S?
modifiziertes Problem P': Gibt es bei einem Array Avon nganzen Zahlen ein 3-Tupel von Adieser Summe bis Null?
Beachten Sie, dass Sie von dieser Version des Problems gehen kann P'von der Pdurch Subtrahieren Ihre S / 3 von jedem Element in A, aber jetzt müssen Sie nicht den Zielwert mehr benötigen.
Wenn wir einfach alle möglichen 3-Tupel testen, lösen wir das Problem in O (n 3 ) - das ist die Brute-Force-Basislinie. Kann man es besser machen? Was ist, wenn wir die Tupel etwas intelligenter auswählen?
Zuerst investieren wir etwas Zeit, um das Array zu sortieren, was uns eine anfängliche Strafe von O (n log n) kostet. Nun führen wir diesen Algorithmus aus:
for (i in 1..n-2) {
j = i+1 // Start right after i.
k = n // Start at the end of the array.
while (k >= j) {
// We got a match! All done.
if (A[i] + A[j] + A[k] == 0) return (A[i], A[j], A[k])
// We didn't match. Let's try to get a little closer:
// If the sum was too big, decrement k.
// If the sum was too small, increment j.
(A[i] + A[j] + A[k] > 0) ? k-- : j++
}
// When the while-loop finishes, j and k have passed each other and there's
// no more useful combinations that we can try with this i.
}
Dieser Algorithmus funktioniert durch drei Zeiger platzieren, i, j, und kan verschiedenen Stellen in der Anordnung. ibeginnt am Anfang und arbeitet sich langsam bis zum Ende vor. kzeigt auf das allerletzte Element. jzeigt darauf, wo ibei begonnen hat. Wir versuchen iterativ, die Elemente an ihren jeweiligen Indizes zu summieren, und jedes Mal passiert eines der folgenden Ereignisse:
- Die Summe ist genau richtig! Wir haben die Antwort gefunden.
- Die Summe war zu klein. Gehen Sie
jnäher an das Ende heran, um die nächstgrößere Zahl auszuwählen.
- Die Summe war zu groß. Gehen Sie
knäher an den Anfang, um die nächstkleinere Zahl auszuwählen.
Für jeden inähern sich die Zeiger von jund kallmählich an. Irgendwann werden sie sich überholen, und an diesem Punkt müssen wir nichts anderes dafür versuchen i, da wir die gleichen Elemente nur in einer anderen Reihenfolge summieren würden. Nach diesem Punkt versuchen wir den nächsten iund wiederholen.
Schließlich werden wir entweder die nützlichen Möglichkeiten ausschöpfen oder die Lösung finden. Sie können sehen, dass dies O (n 2 ) ist, da wir die äußere Schleife O (n) mal ausführen und die innere Schleife O (n) mal ausführen. Es ist möglich, dies subquadratisch zu tun, wenn Sie wirklich Lust haben, indem Sie jede ganze Zahl als Bitvektor darstellen und eine schnelle Fourier-Transformation durchführen, aber das geht über den Rahmen dieser Antwort hinaus.
Hinweis: Da es sich um eine Interviewfrage handelt, habe ich hier ein wenig geschummelt: Dieser Algorithmus ermöglicht die mehrfache Auswahl desselben Elements. Das heißt, (-1, -1, 2) wäre eine gültige Lösung, ebenso wie (0, 0, 0). Es werden auch nur die genauen Antworten gefunden, nicht die nächstgelegene Antwort, wie im Titel erwähnt. Als Übung für den Leser werde ich Sie herausfinden lassen, wie es nur mit bestimmten Elementen (aber es ist eine sehr einfache Änderung) und genauen Antworten (was auch eine einfache Änderung ist) funktioniert.