Eine der beliebtesten Fragen aus den Bereichen Datenstruktur und Algorithmus, die meistens beim Telefoninterview gestellt werden.
Eine der beliebtesten Fragen aus den Bereichen Datenstruktur und Algorithmus, die meistens beim Telefoninterview gestellt werden.
Antworten:
Durch Schummeln und zwei Durchgänge gleichzeitig, parallel. Aber ich weiß nicht, ob das den Personalvermittlern gefallen wird.
Kann mit einem netten Trick auf einer einzelnen verknüpften Liste ausgeführt werden. Zwei Zeiger bewegen sich über die Liste, einer mit doppelter Geschwindigkeit. Wenn der Schnelle das Ende erreicht, ist der andere auf halbem Weg.
Wenn es sich nicht um eine doppelt verknüpfte Liste handelt, können Sie einfach eine Liste zählen und verwenden. Dies erfordert jedoch im schlimmsten Fall eine Verdoppelung des Arbeitsspeichers, und es funktioniert einfach nicht, wenn die Liste zu groß ist, um im Arbeitsspeicher gespeichert zu werden.
Eine einfache, fast alberne Lösung besteht darin, den mittleren Knoten alle zwei Knoten zu erhöhen
function middle(start) {
var middle = start
var nextnode = start
var do_increment = false;
while (nextnode.next != null) {
if (do_increment) {
middle = middle.next;
}
do_increment = !do_increment;
nextnode = nextnode.next;
}
return middle;
}
Wenn es sich um eine doppelt verknüpfte Liste handelt, iterieren Sie an beiden Enden
function middle(start, end) {
do_advance_start = false;
while(start !== end && start && end) {
if (do_advance_start) {
start = start.next
}
else {
end = end.prev
}
do_advance_start = !do_advance_start
}
return (start === end) ? start : null;
}
Gegeben [1, 2, 3] => 2
1, 3
1, 2
2, 2
Gegeben [1, 2] => 1
1, 2
1, 1
Gegeben [1] => 1
Gegeben [] => null
Erstellen Sie ein dynamisches Array, bei dem jedes Element des Arrays beginnend mit dem Anfang ein Zeiger auf jeden Knoten in der Liste ist. Erstellen Sie eine auf 1 initialisierte Ganzzahl, die protokolliert, wie viele Knoten Sie besucht haben (die sich jedes Mal erhöht, wenn Sie zu einem neuen Knoten wechseln). Wenn Sie am Ende angelangt sind, wissen Sie, wie groß die Liste ist, und Sie haben ein geordnetes Array von Zeigern auf jeden Knoten. Teilen Sie abschließend die Größe der Liste durch 2 (und subtrahieren Sie 1 für die 0-basierte Indizierung) und rufen Sie den Zeiger ab, der in diesem Index des Arrays enthalten ist. Wenn die Größe der Liste ungerade ist, können Sie auswählen, welches Element zurückgegeben werden soll (das erste Element werde ich weiterhin zurückgeben).
Hier ist etwas Java-Code, der den Punkt vermittelt (auch wenn die Idee eines dynamischen Arrays ein bisschen wackelig sein wird). Ich würde C / C ++ zur Verfügung stellen, aber ich bin in diesem Bereich sehr rostig.
public Node getMiddleNode(List<Node> nodes){
int size = 1;
//add code to dynamically increase size if at capacity after adding
Node[] pointers = new Node[10];
for (int i = 0; i < nodes.size(); i++){
//remember to dynamically allocate more space if needed
pointers[i] = nodes.get(i);
size++;
}
return pointers[(size - 1)/2];
}
Wird eine Rekursion als mehr als ein Durchgang betrachtet?
Durchlaufen Sie die Liste bis zum Ende und übergeben Sie eine Ganzzahl als Referenz. Erstellen Sie auf jeder Ebene eine lokale Kopie dieses Werts, um später darauf zu verweisen, und erhöhen Sie die Ref-Anzahl, die beim nächsten Aufruf verwendet wird.
Teilen Sie die Anzahl auf dem letzten Knoten durch zwei und kürzen Sie / floor () das Ergebnis (wenn Sie möchten, dass der erste Knoten die "Mitte" ist, wenn es nur zwei Elemente gibt) oder runden Sie auf (wenn Sie möchten, dass der zweite Knoten ist) die Mitte"). Verwenden Sie einen auf Null oder Eins basierenden Index entsprechend.
Ordnen Sie die Anzahl der Referenzen der lokalen Kopie zu (dies ist die Nummer des Knotens). Wenn gleich, geben Sie diesen Knoten zurück. else return Der vom rekursiven Aufruf zurückgegebene Knoten.
.
Es gibt andere Möglichkeiten, dies zu tun. Einige von ihnen sind möglicherweise weniger umständlich (ich dachte, ich hätte jemanden sagen sehen, der es in ein Array einliest und die Array-Länge verwendet, um das mittlere Lob zu bestimmen). Aber ehrlich gesagt gibt es keine guten Antworten, denn es ist eine blöde Interviewfrage. Nummer eins, die immer noch verknüpfte Listen verwendet ( unterstützende Meinung ); Zweitens ist das Finden des mittleren Knotens eine willkürliche, akademische Übung, die in realen Szenarien keinen Wert hat. Drittens, wenn ich den mittleren Knoten wirklich kennen müsste, würde meine verknüpfte Liste eine Knotenzahl anzeigen. Es ist hella einfacher, diese Eigenschaft beizubehalten, als jedes Mal, wenn ich den mittleren Knoten möchte, Zeit zu verschwenden, um die gesamte Liste zu durchlaufen. Und schließlich, vier, wird jeder Interviewer unterschiedliche Antworten mögen oder ablehnen - was ein Interviewer für schlau hält, wird ein anderer für lächerlich halten.
Ich beantworte Interviewfragen fast immer mit mehr Fragen. Wenn ich eine solche Frage bekomme (habe ich nie), würde ich fragen: (1) Was speichern Sie in dieser verknüpften Liste, und gibt es eine geeignetere Struktur, um effizient auf den mittleren Knoten zuzugreifen, wenn dies wirklich erforderlich ist ; (2) Was sind meine Einschränkungen? Ich kann es schneller machen, wenn der Speicher kein Problem darstellt (z. B. die Array-Antwort), aber wenn der Interviewer den Eindruck hat, dass Speicherplatz verschwenderisch ist, werde ich süchtig. (3) In welcher Sprache werde ich mich entwickeln? Nahezu jede moderne Sprache, die ich kenne, verfügt über integrierte Klassen für den Umgang mit verknüpften Listen, die das Durchlaufen der Liste unnötig machen. Warum etwas neu erfinden, das von den Entwicklern der Sprache auf Effizienz hin optimiert wurde?
Mit 2 Zeigern. Inkrementieren Sie eine bei jeder Iteration und die andere bei jeder zweiten Iteration. Wenn der erste Zeiger auf das Ende der verknüpften Liste zeigt, zeigt der zweite Zeiger auf den mittleren Modus der verknüpften Liste.