Is Subsequence
Otrzymujesz dwa ciągi znaków: s i t. Zwróć true, jeśli możesz przekształcić t w s, usuwając niektóre litery (możesz nie usuwać żadnej), tak aby pozostałe litery zachowały swoją kolejność, a w przeciwnym razie zwróć false. Na przykład ace jest podciągiem abcde, ale aec nim nie jest.
Funkcja
- sstring
- ciąg znaków, którego należy szukać
- tstring
- ciąg znaków, z którego należy usunąć litery
- Zwracaboolean
- prawda, jeśli s można odczytać w t w tej samej kolejności, ale z możliwymi przerwami
Ograniczenia
1 ≤ s.length ≤ 3 × 1041 ≤ t.length ≤ 5 × 104sitzawierają wyłącznie małe litery alfabetu angielskiego.
Przykłady
- Wejście
- s = "ace"t = "abcde"
- Wyjście
- true
- Wyjaśnienie
- Usuń
bidzabcde, a pozostanieacew tej samej kolejności.
- Wejście
- s = "aec"t = "abcde"
- Wyjście
- false
- Wyjaśnienie
tma wszystkie trzy litery, ale jedynecznajduje się przed jedynyme. Po użyciueo indeksie 4 po jego prawej stronie nie zostaje już żadnec.
- Wejście
- s = "moon"t = "monsoon"
- Wyjście
- true
- Wyjaśnienie
- Użyj
mna indeksie 0, literona indeksach 1 i 4 oraznna indeksie 6 wmonsoon. Litery pomiędzy nimi są usuwane.
Pytanie dodatkowe
Jeśli t pozostaje niezmienne i sprawdzasz milion ciągów znaków s pod jego kątem, jak przygotujesz t, aby każde sprawdzenie było szybsze niż odczytanie całego t?
Podpowiedzi
Otwieraj je po kolei. Każda zdradza trochę więcej.
Spójrz na pierwszą literę w
s. Której kopii tej litery wtużyć?Użyj najwcześniejszej kopii. Wybranie późniejszej może jedynie pozostawić mniej
tdla pozostałej częścis, więc najwcześniejszy wybór nigdy nie jest gorszy.Utrzymuj jeden indeks w
si jeden wt. Przechodź przeztlitera po literze, przy każdym dopasowaniu przesuwaj indeks wsi na końcu sprawdź, czy dotarł do końcas.
Rozwiązanie
Podciąg może pomijać litery z t w dowolnym miejscu, co sugeruje wypróbowanie wielu rozmieszczeń s. Nie musisz tego robić: dopasowanie każdej litery z s w najwcześniejszym możliwym miejscu nigdy nie jest gorsze od żadnego innego wyboru, więc wystarczy jedno przejście od lewej do prawej z użyciem dwóch wskaźników.
Programowanie dynamiczne na prefiksach
Poprawne, ale nie kończy się na największych testach
Intuicja
Niech dp[i][j] określa, czy pierwsze i liter ciągu s mieszczą się w pierwszych j literach ciągu t. Mieszczą się, jeśli mieszczą się już bez t[j-1] albo jeśli s[i-1] jest równe t[j-1] i pierwsze i-1 liter mieszczą się w t[:j-1]. Pusty prefiks mieści się wszędzie, a wiersz i odwołuje się tylko do wiersza i-1, więc wystarczą dwa wiersze o długości m+1.
Tablica wypełnia każdą komórkę: dla s o długości 25,000 liter i t o długości 50,000 liter daje to 1.25 × 10^9 komórek.
Algorytm
- Utwórz wiersz
prevzm+1wartościami, wszystkietrue: pusty ciągspasuje do każdego prefiksut. - Dla każdego
iod 1 donutwórz wierszcurzcur[0] = false. - Dla każdego
jod 1 domustawcur[j]nacur[j-1]albo naprev[j-1], gdys[i-1]jest równet[j-1]. - Zastąp
prevprzezcur. - Zwróć
prev[m].
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]Dwa wskaźniki z zachłannym dopasowaniem
Intuicja
Zachowaj wskaźnik i wskazujący na następną literę s, której potrzebujesz, i wybierz jej pierwsze napotkane wystąpienie w t. Ten wybór jest bezpieczny. Jeśli poprawne rozmieszczenie wykorzystuje późniejsze wystąpienie s[i], zamiana go na najwcześniejsze wystąpienie zachowuje kolejność i pozostawia więcej znaków t na pozostałą część s. Zatem jeśli istnieje jakiekolwiek rozmieszczenie, algorytm zachłanny je znajdzie.
Pętla odczytuje każdą literę t najwyżej raz i przechowuje dwa indeksy: czas O(n + m) i pamięć O(1).
Algorytm
- Ustaw
i = 0dlasij = 0dlat. - Gdy oba indeksy znajdują się wewnątrz swoich ciągów znaków, porównaj
s[i]zt[j]. - Jeśli są równe, zwiększ
i. - W każdym przypadku zwiększ
j. - Zwróć informację, czy
ijest równe długościs.
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)
Pułapki i przypadki brzegowe
- Wyszukiwanie każdej litery z
sw dowolnym miejscu wt, zamiast po poprzednim dopasowaniu. W ten sposóbaeczostanie uznane za podciągabcde. - Użycie tej samej kopii litery dwa razy.
noonnie jest podciągiemmoon: jedynen, na indeksie 3, nie może być jednocześnie pierwszą i ostatnią literą. - Zwracanie informacji, czy
jdotarło do końcat. Pętla często kończy się w tym miejscu niezależnie od tego, czy znalezionos; tylkoidaje ci tę informację. - Niezatrzymywanie się, gdy zabraknie znaków w
t. Dlaabciabnależy zwrócićfalse. - Odczytywanie
s[i], gdyidotarło do końcas. W Pythonie lub Javie taki odczyt zgłasza wyjątek, więc przed porównaniem sprawdźi.
Najczęstsze pytania3
Jaka jest złożoność czasowa Is Subsequence?
Rozwiązanie z dwoma wskaźnikami działa w czasie O(n + m), gdzie n i m to długości s i t, i wymaga dodatkowej pamięci O(1). Pętla kończy działanie po co najwyżej m krokach. Utworzenie tablicy prefiksów zajmuje czas O(n × m).
Jaki jest związek między problemem podciągu a najdłuższym wspólnym podciągiem?
s jest podciągiem t wtedy i tylko wtedy, gdy ich najdłuższy wspólny podciąg ma długość n, czyli długość całego s. Tablica prefiksów z pierwszego podejścia to ta, którą tworzysz dla tamtego problemu. Tutaj musisz tylko wiedzieć, czy całe s pasuje, więc wystarczy zachłanne przejście.
Jaka jest różnica między podciągiem a podłańcuchem?
Podciąg jest blokiem kolejnych liter, natomiast podciąg sekwencji może pomijać litery, o ile ich kolejność pozostaje taka sama. ace jest podciągiem sekwencji abcde, ale nie jest jego podciągiem ciągłym. Każdy podciąg ciągły jest podciągiem sekwencji, ale nie odwrotnie.
Podobne zadania
Zadania oparte na tych samych pomysłach. Rozwiązanie dwóch lub trzech utrwala schemat.
def isSubsequence(s, t):
# Napisz kod tutajTest #1
Test #2
Test #3
Argumenty
s = "ace" t = "abcde"
Oczekiwany wynik
true