Während eines Interviews bekam ich folgendes Problem:
Gibt eine Zeichenfolge an, die eine Mischung aus Parens (keine Klammern oder Klammern - nur Parens) mit anderen alphanumerischen Zeichen enthält. Identifizieren Sie alle Parens, die keine passenden Paren haben.
In der Zeichenfolge ") (ab))" enthalten die Indizes 0 und 5 beispielsweise Parens, die keine passenden Paren haben.
Ich schlug eine funktionierende O (n) -Lösung vor, die O (n) -Speicher verwendet, einen Stapel verwendet und die Zeichenfolge durchläuft, sobald ich dem Stapel Parens hinzufüge und sie vom Stapel entferne, wenn ich auf einen schließenden Paren stoße und die Oberseite des Stapels enthält ein Eröffnungsparen.
Anschließend stellte der Interviewer fest, dass das Problem in linearer Zeit mit konstantem Speicher gelöst werden kann (wie in, keine zusätzliche Speichernutzung außer dem, was von der Eingabe belegt wird).
Ich fragte, wie und sie sagte etwas darüber, einmal von links durch die Schnur zu gehen und alle offenen Parens zu identifizieren, und dann ein zweites Mal von rechts, alle engen Parens zu identifizieren ... oder vielleicht war es umgekehrt. Ich verstand es nicht wirklich und wollte sie nicht bitten, mich durch die Hand zu halten.
Kann jemand die von ihr vorgeschlagene Lösung klären?
quelle
Antworten:
Sie können das Grundprinzip des von Ihnen verwendeten Algorithmus beibehalten. Sie haben eine Gelegenheit zur Speicheroptimierung verpasst.
Was enthält dieser Stapel? Es wird niemals enthalten
()
(eine öffnende Klammer, gefolgt von einer schließenden Klammer), da Sie immer dann, wenn)
Sie erscheinen, die Pop- Klammer öffnen,(
anstatt die zu drücken)
. Der Stapel hat also immer die Form)…)(…(
- eine Reihe von schließenden Klammern, gefolgt von einer Reihe von öffnenden Klammern.Sie benötigen keinen Stapel, um dies darzustellen. Denken Sie nur an die Anzahl der schließenden Klammern und die Anzahl der öffnenden Klammern.
Wenn Sie die Zeichenfolge mit diesen beiden Zählern von links nach rechts verarbeiten, haben Sie am Ende die Anzahl der nicht übereinstimmenden schließenden Klammern und die Anzahl der nicht übereinstimmenden öffnenden Klammern.
Zusammenfassend: Verarbeiten Sie die Zeichenfolge von links nach rechts. Pflegen Sie einen Zähler mit nicht übereinstimmenden öffnenden Klammern. Wenn Sie eine öffnende Klammer sehen, erhöhen Sie den Zähler. Wenn Sie eine schließende Klammer sehen und der Zähler ungleich Null ist, dekrementieren Sie den Zähler. Wenn Sie eine schließende Klammer sehen und der Zähler Null ist, geben Sie den aktuellen Index als nicht übereinstimmende schließende Klammer aus.
Der Endwert des Zählers ist die Anzahl der nicht übereinstimmenden öffnenden Klammern, aber dies gibt Ihnen nicht ihre Position. Beachten Sie, dass das Problem symmetrisch ist. Führen Sie den Algorithmus einfach in die entgegengesetzte Richtung aus, um die Positionen nicht übereinstimmender öffnender Klammern aufzulisten.
Übung 1: Schreiben Sie dies in einer formalen Notation auf (Mathematik, Pseudocode oder Ihre bevorzugte Programmiersprache).
Übung 2: Überzeugen Sie sich selbst, dass dies der gleiche Algorithmus wie Apass.Jack ist , der nur anders erklärt wurde.
quelle
(()
.Da wir einfach alle alphanumerischen Zeichen ignorieren können, gehen wir davon aus, dass die Zeichenfolge von nun an nur noch Klammern enthält. Wie in der Frage gibt es nur eine Art von Klammern: "()".
Wenn wir ausgeglichene Klammern so lange entfernen, bis keine ausgeglichenen Klammern mehr entfernt werden können, müssen alle verbleibenden Klammern wie folgt aussehen: ")) ...) ((... ("), die alle unausgeglichene Klammern sind. Diese Beobachtung legt nahe, dass wir zuerst diesen Wendepunkt finden sollten , vor denen wir nur unausgeglichene schließende Klammern haben und nach denen wir nur unausgeglichene öffnende Klammern haben.
Hier ist der Algorithmus. Kurz gesagt, es berechnet zuerst den Wendepunkt. Anschließend wird eine zusätzliche schließende Klammer ausgegeben, in der die Zeichenfolge von Anfang nach rechts bis zum Wendepunkt gescannt wird. Symmetrisch wird eine zusätzliche öffnende Klammer ausgegeben, die vom Ende nach links bis zum Wendepunkt scannt.
str
Initialisieren
turning_point=0, maximum_count=0, count=0
. Für jedeni
von0
bisn-1
folgendes zu tun.str[i] = ')'
, addiere 1 zucount
; Andernfalls subtrahieren Sie 1.count > maximum_count
, setzenturning_point=i
undmaximum_count=count
.Jetzt
turning_point
ist der Index des Wendepunktes.Zurücksetzen
maximum_count=0, count=0
. Für jedeni
von0
bisturning_point
folgendes zu tun.str[i] = ')'
, addiere 1 zucount
; Andernfalls subtrahieren Sie 1.count > maximum_count
, setzenmaximum_count = count
. Ausgabei
als Index einer unausgeglichenen schließenden Klammer.Zurücksetzen
maximum_count=0, count=0
. Führen Sie für jedesi
vonn-1
bisturning_point+1
nach unten die folgenden Schritte aus .str[j] = '('
, addiere 1 zucount
; Andernfalls subtrahieren Sie 1.count > maximum_count
, setzenmaximum_count = count
. Ausgabei
als Index einer unausgeglichenen öffnenden Klammer.Wenn wir den obigen Algorithmus analysieren, werden wir sehen, dass wir den Wendepunkt überhaupt nicht finden und verwenden müssen. Die nette Beobachtung, dass alle unausgeglichenen schließenden Klammern vor allen unausgeglichenen öffnenden Klammern auftreten, kann ignoriert werden, obwohl dies interessant ist.
Hier ist Code in Python .
Klicken Sie einfach auf "Ausführen", um mehrere Testergebnisse anzuzeigen.
Übung 1. Zeigen Sie, dass der obige Algorithmus einen Satz von Klammern mit der geringsten Kardinalität ausgibt, sodass die verbleibenden Klammern ausgeglichen sind.
Problem 1. Können wir den Algorithmus auf den Fall verallgemeinern, dass die Zeichenfolge zwei Arten von Klammern enthält, z. B. "() []"? Wir müssen bestimmen, wie die neue Situation, der Verschachtelungsfall "([)]", erkannt und behandelt werden soll.
quelle