Wie suche ich nach einer Zahl in einem 2d-Array sortiert von links nach rechts und von oben nach unten?
War ich kürzlich dieses interview Frage und ich bin gespannt, was eine gute Lösung wäre.
Sagen, dass ich ein 2d array, wo alle
zahlen im array werden in steigender
Reihenfolge von Links nach rechts und von oben nach
unten.Was ist der beste Weg zu suchen und zu
bestimmen, ob eine target-Zahl ist in die
array?
Nun, meine erste Neigung ist die Verwendung einer binären Suche, da meine Daten sortiert. Ich kann bestimmen, ob eine Zahl in einer einzigen Zeile in O(log N) Zeit. Allerdings ist es die 2 Richtungen, die werfen mich Weg.
Andere Lösung dachte ich kann die Arbeit beginnen irgendwo in der Mitte. Wenn der mittlere Wert ist kleiner als mein Gegner, dann kann ich sicher sein, dass es in das linke quadratische Teil der matrix aus der Mitte. Ich habe dann Diagonal ziehen und erneut prüfen, die Verringerung der Größe des Quadrats, das Ziel könnte möglicherweise sein, bis ich geschliffen in auf die Ziel-Nummer.
Hat jemand irgendwelche guten Ideen zur Lösung dieses Problems?
Beispiel-array:
Sortiert von Links nach rechts, oben nach unten.
1 2 4 5 6
2 3 5 7 8
4 6 8 9 10
5 8 9 10 11
[[1 1][1 1]]
? InformationsquelleAutor der Frage Phukab | 2010-03-16
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ist hier eine einfache Herangehensweise:
Für eine
NxM
array, das läuft inO(N+M)
. Ich denke, es wäre schwierig, besser zu tun. 🙂Edit: Viele gute Diskussionen. Ich Sprach über den Allgemeinen Fall oben; klar, wenn
N
oderM
klein sind, könnte man eine binäre Suche Ansatz, dies zu tun in so etwas wie logarithmische Zeit.Hier sind einige details, für diejenigen, die neugierig sind:
Geschichte
Dieser einfache Algorithmus wird als eine Saddleback Suche. Es ist schon eine Weile herum, und es ist optimal, wenn
N == M
. Einige Referenzen:Jedoch, wenn
N < M
, intuition deutet darauf hin, dass die binäre Suche sollte in der Lage sein, es besser zu machen alsO(N+M)
: Zum Beispiel, wennN == 1
eine Reine binäre Suche in logarithmischer statt linearer Zeit.Worst-case-gebunden
Richard Vogel untersucht diese intuition, die binäre Suche verbessern könnte Saddleback-Algorithmus in einer 2006 Papier:
Mit einer eher ungewöhnlichen Lehrmethode, Vogel, zeigt uns, dass für
N <= M
dieses problem eine untere Schranke vonΩ(N * log(M/N))
. Diese Schranke auch Sinn machen, denn es gibt uns die lineare Leistung, wennN == M
- und logarithmische Leistung, wennN == 1
.Algorithmen für rechteckige arrays
Einen Ansatz, verwendet eine Zeile-für-Zeile binäre Suche sieht so aus:
N < M
. Lassen Sie uns sagenN
Zeilen undM
ist Spalten.value
. Wenn wir ihn finden, sind wir fertig.s
undg
, wos < value < g
.s
ist weniger alsvalue
, so können wir vermeiden es.g
größer ist alsvalue
, so können wir vermeiden es.In Bezug auf die worst-case Komplexität dieses Algorithmus ist
log(M)
zu beseitigen Hälfte der möglichen Lösungen, und dann rekursiv ruft sich selbst zweimal auf zwei kleinere Probleme. Wir haben zu wiederholen, eine kleinere version, dielog(M)
Arbeit für jede Zeile, aber wenn die Anzahl der Zeilen ist klein im Vergleich zu der Anzahl der Spalten, dann in der Lage sein zu beseitigen alle diese Spalten in logarithmischer Zeit beginnt sich lohnt.Dies gibt der Algorithmus eine Komplexität von
T(N,M) = log(M) + 2 * T(M/2, N/2)
, die Vogel-shows werdenO(N * log(M/N))
.Ein weiterer Ansatz, geschrieben von Craig Gidney beschreibt einen Algorithmus ähnlich dem Ansatz vor: er prüft eine Zeile zu einem Zeitpunkt mit einer Schrittweite von
M/N
. Seine Analyse zeigt, dass diese Ergebnisse inO(N * log(M/N))
Leistung.Performance-Vergleich
Big-O-Analyse ist ja alles schön und gut, aber wie gut diese Ansätze funktionieren in der Praxis? Das Diagramm unten untersucht vier algorithmen für immer "Platz" - arrays:
(Der "naive" Algorithmus, der einfach durchsucht jedes element des array. Die "rekursiven" Algorithmus, der oben beschrieben ist. Die "hybrid" - Algorithmus ist eine Implementierung von Gidney ' s Algorithmus. Für jede array-Größe, die Leistung wurde gemessen, indem das timing jeder Algorithmus über festen Satz in Höhe von 1.000.000, zufällig generierten arrays.)
Einige Bemerkenswerte Punkte:
Zusammenfassung
Kluge Nutzung der binären Suche kann bieten
O(N * log(M/N)
Leistung für rechteckige und quadratische arrays. DieO(N + M)
"saddleback" - Algorithmus ist viel einfacher, aber leidet unter Leistungsabfall als arrays werden immer rechteckig.InformationsquelleAutor der Antwort Nate Kohl
Nimmt dieses problem
Θ(b lg(t))
Zeit, wob = min(w,h)
undt=b/max(w,h)
. Ich diskutieren Sie die Lösung in in diesem blog-post.Untere Schranke
Einen Gegner zwingen kann, einen Algorithmus zu machen
Ω(b lg(t))
Abfragen, beschränken sich auf die Hauptdiagonale:Legende: weisse Zellen sind kleinere Gegenstände, die grauen Zellen sind größere Gegenstände, gelbe Zellen sind kleiner-oder-gleich der Elemente und orange-Zellen sind größer-oder-gleich posten. Der Widersacher Kräfte die Lösung sein, je nachdem, was gelb oder orange Zelle der Algorithmus Abfragen Letzte.
Feststellen, dass es
b
unabhängige sortierte Listen von Größet
erfordernΩ(b lg(t))
Abfragen vollständig zu eliminieren.Algorithmus
w >= h
)t
auf der linken Seite der oberen rechten Ecke des gültigen Bereicht
Zellen in der Zeile mit einer binären Suche. Wenn ein passendes Objekt gefunden wird, während dies zu tun, kehren Sie mit Ihrer position.t
kurze Spalten.Suche nach einem Element:
Bestimmung ein Element nicht existiert:
Legende: weisse Zellen sind kleinere Gegenstände, die grauen Zellen sind größere Gegenstände, und die grüne Zelle ist die gleiche Sache.
Analyse
Gibt es
b*t
kurze Spalten zu beseitigen. Es gibtb
langen Reihen zu beseitigen. Die Beseitigung einer langen Reihe KostenO(lg(t))
Zeit. Die Beseitigungt
kurze Spalten KostenO(1)
Zeit.Im schlimmsten Fall müssen wir beseitigen, jede Spalte und jede Zeile, die Zeit nehmen
O(lg(t)*b + b*t*1/t) = O(b lg(t))
.Beachten Sie, dass ich gehe mal davon aus
lg
Klemmen, um ein Ergebnis über 1 (d.h.lg(x) = log_2(max(2,x))
). Das ist, warum, wennw=h
, Bedeutungt=1
ist, erhalten wir die erwartete GrenzeO(b lg(1)) = O(b) = O(w+h)
.Code
InformationsquelleAutor der Antwort Craig Gidney
Ich würde verwenden Sie die divide-und-conquer-Strategie für dieses problem, ähnlich zu dem, was Sie vorgeschlagen, aber die details sind ein bisschen anders.
Dies wird eine rekursive Suche auf Teilbereiche der matrix.
Bei jedem Schritt, wählen Sie ein element in der Mitte der Reihe. Wenn der Wert gefunden ist, was Sie suchen, dann sind Sie fertig.
Andernfalls, wenn der Wert kleiner ist als der Wert, den Sie suchen, dann wissen Sie, dass es nicht im Quadranten oben und Links von der aktuellen position. So rekursiv suchen die beiden Teilbereiche: alles (ausschließlich) unterhalb der aktuellen position, und alles (ausschließlich) auf das Recht, auf oder oberhalb der aktuellen position.
Andernfalls (der Wert ist größer als der Wert, den Sie suchen) Sie wissen, dass es nicht im Quadranten unterhalb und rechts von Ihrer aktuellen position. So rekursiv suchen die beiden Teilbereiche: alles (ausschließlich) Links von der aktuellen position, und alles (ausschließlich) über die aktuelle position, die ist auf der aktuellen Spalte oder eine Spalte nach rechts.
Ba-da-bing, fand Sie es.
Beachten Sie, dass jeder rekursive Aufruf befasst sich nur mit den aktuellen Teilbereich, nicht (zum Beispiel) ALLE Zeilen oberhalb der aktuellen position. Nur die in der aktuellen Teilbereich.
Hier einige pseudocode für Sie:
InformationsquelleAutor der Antwort Jeffrey L Whitledge
Die zwei wichtigsten Antworten geben, so weit scheinen die wohl
O(log N)
"Zick-Zack-Methode" und dieO(N+M)
Binary-Search-Methode. Ich dachte, ich würde tun einige Tests zum Vergleich der beiden Methoden mit einigen verschiedenen setups. Hier sind die details:Array N x N-Quadrat in jedem test, mit N variieren von 125 bis 8000 (die größte meiner JVM-heap behandeln konnte). Für jede array-Größe, nahm ich eine zufällige Stelle im array ein einziges
2
. Dann legte ich eine3
überall möglich (rechts und unten von 2) und füllten dann den rest des Arrays mit1
. Einige der früheren Kommentatoren schien zu denken, diese Art der Installation würde die Ausbeute worst-case Laufzeit für beide algorithmen. Für jedes array-Größe", ich nahm 100 verschiedenen zufälligen Orten für die 2 (search target) und lief der test. Ich nahm avg Laufzeit und worst-case Laufzeit für jeden Algorithmus. Da war es passiert zu schnell zu gute ms-Messungen in Java, und weil ich nicht Vertrauen Java nanoTime(), wiederholte ich jeden test 1000 mal nur um ein uniform bias-Faktor, zu allen Zeiten. Hier sind die Ergebnisse:Zick-Zack-beat binary in jedem test für beide avg und worst-case Zeiten, aber Sie sind alle in einer Größenordnung von einander mehr oder weniger.
Hier ist der Java code:
InformationsquelleAutor der Antwort The111
Dies ist ein kurzer Beweis der unteren Schranke für das problem.
Können Sie nicht besser als die lineare Zeit (in Bezug auf die Dimensionen des Arrays, nicht die Anzahl der Elemente). Im unteren Bereich jedes der Elemente, gekennzeichnet als
*
können entweder 5 oder 6 (unabhängig von anderen). Also, wenn Ihr Ziel nicht Wert ist 6 (oder 5) muss der Algorithmus überprüfen Sie alle von Ihnen.Natürlich erweitert, um größere arrays. Dies bedeutet, dass diese Antwort optimal ist.
Update: Wie bereits von Jeffrey L Whitledge, es ist nur optimal, wie die asymptotische untere Schranke für die Laufzeit vs input-Daten Größe (behandelt als eine einzelne variable). Laufzeit als zwei-Variablen-Funktion auf beiden array-Dimensionen verbessert werden kann.
InformationsquelleAutor der Antwort Rafał Dowgird
Ich denke, Hier ist die Antwort und es funktioniert für jede Art der sortierten matrix
InformationsquelleAutor der Antwort Sridhar Ravipati
Interessante Frage. Betrachten Sie diese Idee - erstellen Sie eine Grenze, wo alle zahlen, die größer sind als Ihre Zielgruppe und anderen, wo alle zahlen sind kleiner als Ihre Gegner. Wenn etwas übrig ist, zwischen den beiden, das ist Ihr Ziel.
Wenn ich mich für 3 in deinem Beispiel, ich Lesen Sie über die erste Zeile, bis ich die Treffer 4, dann für die kleinste benachbarte Zahl (einschließlich der diagonalen) größer als 3:
1 2 4 5 6
2 3 5 7 8
4 6 8 9 10
5 8 9 10 11
Nun Tue ich das gleiche für diejenigen, die zahlen weniger als 3:
1 2 4 5 6
2 3 5 7 8
4 6 8 9 10
5 8 9 10 11
Nun Frage ich, ist alles, was in den beiden Grenzen? Wenn ja, es müssen 3 sein. Wenn Nein, dann gibt es keine 3. Art der indirekten, da ich eigentlich gar nicht finden, die Anzahl, die ich nur folgern, dass es vorhanden sein muss. Dies hat den zusätzlichen bonus von zählen ALLE 3.
Ich versuchte dies auf einige Beispiele, und es scheint zu funktionieren OK.
InformationsquelleAutor der Antwort Grembo
Binäre Suche durch die Diagonale des Arrays ist die beste option.
Wir finden heraus, ob das element kleiner oder gleich den Elementen in der diagonalen.
InformationsquelleAutor der Antwort Nikhil K R
A. Tun, eine binäre Suche auf den Zeilen, in denen die Ziel-Nummer auf sein.
B. Machen Sie ein Diagramm : achten Sie auf die Anzahl von nehmen immer die kleinste unbesuchte Nachbar-Knoten und backtracking, wenn ein zu großer Anzahl gefunden wird
InformationsquelleAutor der Antwort Tuomas Pelkonen
Binäre Suche wäre die beste Lösung, imo. Ab 1/2-x, 1/2-y, wird es in die Hälfte geschnitten. DH ein 5x5 Quadrat wäre so etwas wie x == 2 /y == 3 . Abgerundet ich einen Wert nach unten und ein Wert von bis zu besseren zone in der Richtung des angestrebten Wert.
Für Klarheit die nächste iteration geben würde, Sie so etwas wie x == 1 /y == 2 ODER x == 3 /y == 5
InformationsquelleAutor der Antwort Woot4Moo
Nun, um zu beginnen, lassen Sie uns annehmen, wir sind mit einem Quadrat.
1. Suche einen Platz
Ich würde verwenden eine binäre Suche auf der diagonalen. Das Ziel ist, suchen Sie die kleinere Zahl, dass ist nicht unbedingt niedriger als die Ziel-Nummer.
Sagen, ich bin auf der Suche nach
4
zum Beispiel, dann würde ich am Ende der Lokalisierung5
bei(2,2)
.Dann, ich bin sicher, dass, wenn
4
ist in der Tabelle, es ist an einer position entweder(x,2)
oder(2,x)
mitx
im[0,2]
. Gut, das ist nur 2 binäre Suche.Die Komplexität nicht abschreckend:
O(log(N))
(3 binäre Suche auf Bereiche von LängeN
)2. Suche ein Rechteck, ein naiver Ansatz
Natürlich wird das ein bisschen komplizierter, wenn
N
undM
unterscheiden sich (mit einem Rechteck), sollten Sie diese entarteten Fall:Und sagen wir, ich bin auf der Suche nach
9
... Der Diagonale Ansatz ist immer noch gut, aber die definition der diagonalen ändert. Hier meine Diagonale ist[1, (5 or 6), 17]
. Sagen wir, ich nahm[1,5,17]
, dann weiß ich, dass wenn9
ist in der Tabelle ist es entweder in den Abschnitt:Dies gibt uns 2 Rechtecke:
So können wir recurse! wahrscheinlich Anfang durch die man mit weniger Elementen (obwohl in diesem Fall es tötet uns).
Ich soll zeigen, dass, wenn eine der Dimensionen ist weniger als
3
können wir nicht gelten die Diagonale Methoden und verwenden müssen, eine binäre Suche. Hier würde es bedeuten:10 11 12 13 14 15 16
nicht gefunden5 6 7 8
nicht gefunden6 7 8 9
nicht gefundenEs ist schwierig, weil man eine gute Leistung, die Sie wollen könnten, zu unterscheiden zwischen mehreren Fällen, abhängig von der Allgemeinen Form....
3. Suche ein Rechteck, das brutale Vorgehen
Es wäre viel einfacher, wenn wir befassten uns mit einem Quadrat... also lasst uns einfach Platz machen.
Wir haben jetzt ein Quadrat.
Natürlich werden wir wohl NICHT wirklich schaffen, diese Zeilen könnten wir einfach nacheifern.
also es verhält sich wie ein Quadrat ohne Besatzungsmacht mehr Speicher (auf Kosten der Geschwindigkeit, wahrscheinlich, je nach cache... naja :p)
InformationsquelleAutor der Antwort Matthieu M.
EDIT:
Ich falsch verstanden, die Frage. Wie die Kommentare zeigen dies funktioniert nur in den engeren Fall.
In einer Sprache wie C, die speichert die Daten im row-major order, einfach behandeln es als ein 1D-array der Größe n * m und verwenden eine binäre Suche.
InformationsquelleAutor der Antwort Hugh Brackett
Ich habe einen rekursiven Divide & Conquer-Lösung.
Grundlegende Idee für ein Schritt ist: Wir wissen, dass der Linken-Oberen(LU) ist die kleinste und die rechts unten(RB) ist der größte Nr. also das da Keine(N) muss: N>=LU und N<=RB
WENN N== - LU und N==RB::::Element Gefunden und Abbruch der Rückkehr die position/Index
Wenn N>=LU und N<=RB = FALSE, Nein ist es nicht und bricht ab.
Wenn N>=LU und N<=RB = TRUE, Teilen Sie das 2D-array in 4 gleiche Teile des 2D-array jeweils in logischer Weise..
Und dann gelten die gleichen algo Schritt für alle vier sub-array.
Mein Algo ist Richtig implementierte ich auf meinem PC Freunde.
Komplexität: je 4 Vergleiche b verwendet, um Rückschlüsse auf die Gesamtzahl der Elemente auf ein Viertel im schlimmsten Fall..
Also Mein Komplexität kommt auf 1 + 4 x lg(n) + 4
Aber wirklich erwartet, dass dies auf O(n)
Ich denke, etwas ist falsch irgendwo in meiner Berechnung der Komplexität, bitte korrigieren wenn dem so ist..
InformationsquelleAutor der Antwort Pervez Alam
Die optimale Lösung ist, um zu beginnen in der oberen linken Ecke,, die hat einen minimalen Wert. Verschieben Diagonal nach unten rechts, bis Sie auf ein element, dessen Wert >= Wert des Elements. Wenn das element Wert ist gleich dem Wert des angegebenen Elements zurück gefunden, wie wahr.
Ansonsten, von hier aus können wir gehen, gibt es zwei Möglichkeiten.
Strategie 1:
Strategie 2:
Lasse ich die Bezeichnung der Zeilenindex und j bezeichnen die Spalte index der Diagonale element, das wir aufgehört haben. (Hier haben wir i = j, BTW). Let k = 1.
1 2 4 5 6
2 3 5 7 8
4 6 8 9 10
5 8 9 10 11
InformationsquelleAutor der Antwort Murali Mohan
InformationsquelleAutor der Antwort gsb
Schlage ich vor, speichern Sie alle Zeichen in einem
2D list
. dann finden Sie den index des gewünschten Elements, wenn es vorhanden ist in der Liste.Wenn nicht Druck auf die entsprechende Meldung else print (Zeile und Spalte) als:
row = (index/total_columns)
undcolumn = (index%total_columns -1)
Fällt nur die binäre Suche Zeit in einer Liste.
Bitte machen Sie eventuelle Korrekturen. 🙂
InformationsquelleAutor der Antwort Abhi31jeet
Wenn O(M log(N)) Lösung ist ok für eine MxN-array -
C++ demo.
Bitte lassen Sie mich wissen, wenn dies nicht funktionieren würde, oder wenn es ein bug ist es.
InformationsquelleAutor der Antwort kaushal
Gegeben eine quadratische matrix wie folgt:
Wissen wir, dass ein < c, d < f i < k. Was wir nicht wissen, ist, ob d < c oder d - > c usw.. Wir haben garantiert nur in 1 dimension.
Blick auf die end-Elemente (c,f,k), wir können eine Art von filter: ist N < c ? search() : next(). Damit haben wir n Iterationen über die Zeilen, wobei jede Zeile der Einnahme von entweder O( log( n ) ) binäre Suche oder O( 1 ) wird gefiltert.
Lassen Sie mich ein BEISPIEL gegeben, wobei N = j,
Versuchen Sie es erneut mit N = q,
Es gibt vermutlich eine bessere Lösung gibt, aber das ist einfach zu erklären.. 🙂
InformationsquelleAutor der Antwort apandit
Da dieses eine interview-Frage, es würde scheinen, führen zu einer Diskussion der Parallele Programmierung und Map-reduce algorithmen.
Sehen http://code.google.com/intl/de/edu/parallel/mapreduce-tutorial.html
InformationsquelleAutor der Antwort GarethOwen