Is Subsequence
Du erhältst zwei Zeichenfolgen, s und t. Gib true zurück, wenn du t in s umwandeln kannst, indem du einige seiner Buchstaben löschst (möglicherweise auch keine), während die verbleibenden Buchstaben ihre Reihenfolge beibehalten, und andernfalls false. Zum Beispiel ist ace eine Teilfolge von abcde, aber aec ist es nicht.
Funktion
- sstring
- die zu suchende Zeichenfolge
- tstring
- die Zeichenfolge, aus der Buchstaben gelöscht werden sollen
- Gibt zurückboolean
- wahr, wenn s innerhalb von t der Reihenfolge nach gelesen werden kann, möglicherweise mit Lücken
Einschränkungen
1 ≤ s.length ≤ 3 × 1041 ≤ t.length ≤ 5 × 104sundtenthalten nur englische Kleinbuchstaben.
Beispiele
- Eingabe
- s = "ace"t = "abcde"
- Ausgabe
- true
- Erklärung
- Wenn du
bunddausabcdelöschst, bleibtacein derselben Reihenfolge übrig.
- Eingabe
- s = "aec"t = "abcde"
- Ausgabe
- false
- Erklärung
tenthält alle drei Buchstaben, aber das einzigecsteht vor dem einzigene. Nachdem du dasean Index 4 verwendest, bleibt rechts davon keincübrig.
- Eingabe
- s = "moon"t = "monsoon"
- Ausgabe
- true
- Erklärung
- Verwende das
mam Index 0, dieos an den Indizes 1 und 4 sowie dasnam Index 6 vonmonsoon. Die Buchstaben dazwischen werden gelöscht.
Weiterführende Frage
Wenn t unverändert bleibt und du eine Million Zeichenketten s damit vergleichst, wie würdest du t vorbereiten, damit jeder Vergleich schneller ist, als ganz t zu lesen?
Tipps
Öffne sie nacheinander. Jeder verrät ein bisschen mehr.
Sieh dir den ersten Buchstaben von
san. Welche Kopie davon intsolltest du verwenden?Verwende die früheste Kopie. Eine spätere zu nehmen kann für den Rest von
snur weniger vontübrig lassen, daher ist die früheste Wahl niemals schlechter.Behalte einen Index in
sund einen int. GehetBuchstabe für Buchstabe durch, rücke den Index insbei jeder Übereinstimmung vor und prüfe am Ende, ob das Ende vonserreicht wurde.
Lösung
Eine Teilsequenz darf an beliebigen Stellen Buchstaben von t überspringen, was darauf hindeutet, viele Platzierungen von s auszuprobieren. Das ist nicht nötig: Jeden Buchstaben von s an der frühestmöglichen Stelle zuzuordnen, ist nie schlechter als jede andere Wahl. Daher genügt ein Durchlauf von links nach rechts mit zwei Zeigern.
Dynamische Programmierung über Präfixe
Korrekt, wird aber bei den größten Tests nicht fertig
Idee
Sei dp[i][j] ein Indikator dafür, ob die ersten i Buchstaben von s in die ersten j Buchstaben von t passen. Sie passen, wenn sie bereits ohne t[j-1] passen oder wenn s[i-1] gleich t[j-1] ist und die ersten i-1 Buchstaben in t[:j-1] passen. Das leere Präfix passt überall hin, und Zeile i liest nur Zeile i-1, daher reichen zwei Zeilen der Länge m+1 aus.
Die Tabelle füllt jede Zelle: Bei s mit 25.000 Buchstaben und t mit 50.000 sind das 1.25 × 10^9 Zellen.
Algorithmus
- Erstelle eine Zeile
prevmitm+1Werten, die alletruesind: Ein leeresspasst in jedes Präfix vont. - Erstelle für jedes
ivon 1 bisneine Zeilecurmitcur[0] = false. - Setze für jedes
jvon 1 bismcur[j]aufcur[j-1]oder aufprev[j-1], wenns[i-1]gleicht[j-1]ist. - Ersetze
prevdurchcur. - Gib
prev[m]zurück.
def isSubsequence(s, t):
n, m = len(s), len(t)
# prev[j]: the first i-1 letters of s fit inside t[:j]. An empty s fits anywhere.
prev = [True] * (m + 1)
for i in range(1, n + 1):
cur = [False] * (m + 1)
for j in range(1, m + 1):
cur[j] = cur[j - 1] or (s[i - 1] == t[j - 1] and prev[j - 1])
prev = cur
return prev[m]Zwei Zeiger mit gierigem Abgleich
Idee
Behalte einen Zeiger i auf den nächsten Buchstaben von s, den du benötigst, und nimm das erste Vorkommen davon in t, auf das du triffst. Diese Wahl ist sicher. Wenn eine gültige Platzierung ein späteres Vorkommen von s[i] verwendet, erhält man durch den Austausch mit dem frühesten Vorkommen die Reihenfolge und lässt mehr von t für den Rest von s übrig. Wenn es also eine Platzierung gibt, findet der Greedy-Ansatz sie.
Die Schleife liest jeden Buchstaben von t höchstens einmal und behält zwei Indizes: Zeitaufwand O(n + m) und Speicherbedarf O(1).
Algorithmus
- Setze
i = 0fürsundj = 0fürt. - Vergleiche, solange sich beide Indizes innerhalb ihrer Zeichenketten befinden,
s[i]mitt[j]. - Erhöhe
i, wenn sie gleich sind. - Erhöhe
jin jedem Fall. - Gib zurück, ob
ider Länge vonsentspricht.
def isSubsequence(s, t):
i = j = 0
while i < len(s) and j < len(t):
if s[i] == t[j]:
i += 1
j += 1
return i == len(s)
Stolperfallen und Grenzfälle
- Jeden Buchstaben von
sirgendwo intsuchen, statt erst nach dem vorherigen Treffer. Dadurch wirdaecinabcdeakzeptiert. - Einen Buchstaben zweimal verwenden.
noonist keine Teilsequenz vonmoon: Das einzigenan Index 3 kann nicht gleichzeitig der erste und der letzte Buchstabe sein. - Zurückgeben, ob
jdas Ende vonterreicht hat. Die Schleife endet oft dort, unabhängig davon, obsgefunden wurde; nurigibt dir darüber Auskunft. - Nicht anhalten, wenn
taufgebraucht ist.abcim Vergleich mitabmussfalsezurückgeben. s[i]lesen, nachdemidas Ende vonserreicht hat. In Python oder Java löst dieser Lesezugriff einen Fehler aus. Prüfe alsoi, bevor du vergleichst.
Häufige Fragen3
Wie hoch ist die Zeitkomplexität von Is Subsequence?
Die Lösung mit zwei Zeigern benötigt O(n + m) Zeit, wobei n und m die Längen von s und t sind, und O(1) zusätzlichen Speicher. Die Schleife stoppt nach höchstens m Schritten. Die Präfixtabelle benötigt O(n × m) Zeit.
Wie hängt „Is Subsequence“ mit der längsten gemeinsamen Teilsequenz zusammen?
s ist genau dann eine Teilsequenz von t, wenn ihre längste gemeinsame Teilsequenz die Länge n hat, also die von s. Die Präfixtabelle des ersten Ansatzes ist die, die du für dieses Problem erstellst. Hier musst du nur wissen, ob ganz s hineinpasst, daher reicht der Greedy-Durchlauf aus.
Was ist der Unterschied zwischen einer Teilfolge und einem Teilstring?
Ein Teilstring ist ein Block aufeinanderfolgender Buchstaben, während eine Teilsequenz Buchstaben überspringen darf, solange die Reihenfolge gleich bleibt. ace ist eine Teilsequenz von abcde, aber kein Teilstring davon. Jeder Teilstring ist eine Teilsequenz, aber nicht umgekehrt.
Ähnliche Aufgaben
Aufgaben mit denselben Ideen. Wer zwei oder drei davon löst, behält das Muster.
def isSubsequence(s, t):
# Schreibe hier den CodeTest #1
Test #2
Test #3
Argumente
s = "ace" t = "abcde"
Erwartete Ausgabe
true