Is Subsequence
İki dize alırsın: s ve t. Kalan harfler sıralarını korurken t dizisinden bazı harfleri (hiç harf silmemek de mümkün) silerek onu s dizisine dönüştürebiliyorsan true, aksi hâlde false döndür. Örneğin, ace, abcde dizisinin bir alt dizisidir, ancak aec değildir.
Fonksiyon
- sstring
- aranacak dize
- tstring
- Harflerin silineceği dize
- Döndürürboolean
- true, s dizisi t içinde boşluklar bırakılarak da olsa sırayla okunabiliyorsa
Kısıtlar
1 ≤ s.length ≤ 3 × 1041 ≤ t.length ≤ 5 × 104svetyalnızca küçük İngilizce harfler içerir.
Örnekler
- Girdi
- s = "ace"t = "abcde"
- Çıktı
- true
- Açıklama
abcdeiçindenbvedöğelerini silince, aynı sıraylaacekalır.
- Girdi
- s = "aec"t = "abcde"
- Çıktı
- false
- Açıklama
tharfinin üçü de var, ancak tekc, teke'den önce geliyor. 4. indekstekie'yi kullandıktan sonra sağında hiçckalmaz.
- Girdi
- s = "moon"t = "monsoon"
- Çıktı
- true
- Açıklama
monsoondizgesinin 0 indeksindekim'yi, 1 ve 4 indekslerindekio'ları ve 6 indeksindekin'yi kullan. Aradaki harfler silinir.
Gönderirken +20 gizli test
Ek soru
t aynı kalıyor ve buna karşı bir milyon farklı s dizgesini kontrol etmen gerekiyor diyelim. Her kontrolü t'nin tamamını yeniden okumaktan daha hızlı hâle getirmek için t'yi nasıl hazırlardın?
İpuçları
Tek tek açın. Her biri biraz daha fazlasını gösterir.
sharfinin ilk harfine bak.tiçindeki kopyalarından hangisini kullanmalısın?En erken kopyayı kullanın. Daha sonraki bir kopyayı almak,
s’nin geri kalanı için yalnızca daha aztbırakabilir; bu nedenle en erken seçim hiçbir zaman daha kötü değildir.siçinde bir indeks vetiçinde bir indeks tut.tboyunca her seferinde bir harf ilerle, her eşleşmedesiçindeki indeksi ilerlet ve sonundas'nin sonuna ulaşıp ulaşmadığını kontrol et.
Çözüm
Bir alt dizi, t içindeki harfleri herhangi bir yerde atlayabilir; bu yüzden s'yi t içine yerleştirmenin birçok yolunu denemeniz gerekiyormuş gibi görünebilir. Gerek yok. s'nin her harfini yerleştirilebileceği en erken yerde eşleştirmek, başka herhangi bir seçimden asla daha kötü değildir ve böylece arama, iki işaretçiyle soldan sağa tek bir geçişe dönüşür.
Önekler üzerinde dinamik programlama
Doğru, ama en büyük testlerde bitmiyor
Sezgi
Daha küçük bir soru sor: s dizisinin ilk i harfi, t dizisinin ilk j harfinin içine sığar mı? Yanıta dp[i][j] diyelim. Eğer s dizisinin ilk i harfi t[:j-1] içine sığıyorsa, t[j-1] karakterini silebileceğin için t[:j] içine de sığar. s[i-1], t[j-1] ile eşitse bu harfi de kullanabilirsin; bu durumda s dizisinin ilk i-1 harfi t[:j-1] içine sığmalıdır. Dolayısıyla dp[i][j] = dp[i][j-1] or (s[i-1] == t[j-1] and dp[i-1][j-1]) olur ve s dizisinin boş öneki her yere sığar.
i. satır yalnızca i-1. satırı okur; bu nedenle m+1 uzunluğunda iki satır yeterlidir. Yanıt, son satırın son hücresidir.
Bu, en uzun ortak alt diziyi bulmak için oluşturduğun tablonun aynısıdır ve doğrudur, ancak her hücreyi doldurur. s dizisi 25,000 harf ve t dizisi 50,000 harf içerdiğinde bu, 1.25 × 10^9 hücre demektir; iki dizinin üzerinden tek bir geçişin gerektirdiğinden çok daha fazlası.
Algoritma
- Tüm değerleri
trueolan,m+1değerlik birprevsatırı oluştur: boş birs,t'nin her önekine uyar. - 1'den
n'ye kadar heriiçin,cur[0] = falseolan bircursatırı oluştur. - 1'den
m'ye kadar herjiçin,s[i-1]ilet[j-1]eşitsecur[j]'yicur[j-1]ya daprev[j-1]olarak ayarla. prev'icurile değiştir.prev[m]'yi döndür.
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]Greedy eşleştirmeyle iki işaretçi
Sezgi
t dizgesini soldan sağa oku ve hâlâ s dizgesinin sıradaki harfine ihtiyaç duyduğun konumu gösteren i işaretçisini tut. t[j], s[i] ile eşleştiğinde onu kullan ve i değerini ilerlet. Her durumda j değerini ilerlet. i, s dizgesinin sonuna ulaşırsa tüm harfler sırayla bir yer bulmuş demektir.
İlk eşleşmeyi almak neden güvenlidir? Geçerli bir yerleşimin s[i] harfinin daha sonraki bir kopyasını kullandığını varsayalım. Bunu en erken kopyayla değiştirmek sırayı korur ve s dizgesinin geri kalanı için t dizgesinin sağında daha fazla yer bırakır; dolayısıyla açgözlü seçim, var olan bir yerleşimi asla kaybettirmez. moon için monsoon dizgesinde işaretçi 1. indeksteki o harfini alır, n ve s harflerini atlar, 4. indeksteki o harfini alır ve 6. indeksteki n harfinde sona erer.
j, t dizgesindeki her harfi bir kez ziyaret eder ve i yalnızca ileri hareket eder; bu nedenle döngü en fazla m kez çalışır. İhtiyaç duyduğu bellek yalnızca iki indextir.
Algoritma
siçini = 0vetiçinj = 0ayarla.- Her iki dizin de dizelerinin içindeyken
s[i]ilet[j]değerlerini karşılaştır. - Eşitlerse
ideğerini artır. - Her durumda
jdeğerini artır. ideğerininsuzunluğuna eşit olup olmadığını döndür.
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)
Tuzaklar ve uç durumlar
İki işaretçili döngü kısadır ve hataları uç durumlarda ortaya çıkar.
siçindeki her harfi, önceki eşleşmeden sonra aramak yerinetiçinde herhangi bir yerde aramak. Bu, sıralamanın bozulduğuabcdeiçindeaecdizisini kabul eder.- Bir harfin aynı kopyasını iki kez kullanmak.
noon,moondizisinin bir alt dizisi değildir:mooniçinde 3. indekste tek birnvardır ve bu harfnoondizisinin hem ilk hem de son harfi olamaz. jdeğerinintdizisinin sonuna ulaşıp ulaşmadığını döndürmek. Döngü,sbulunmuş olsun ya da olmasın çoğu zaman orada biter; size yalnızcaibilgi verir.sdizisinintdizisinden daha uzun olabileceğini unutmak.abdizisine karşıabciçinfalsedöndürülmelidir; döngü,ttükendiğinde durduğu sürece bunu sağlar.i,sdizisinin sonuna ulaştıktan sonras[i]değerini okumak. Python veya Java'da bu okuma hata verir; bu yüzden karşılaştırma yapmadan önceideğerini kontrol edin.
Sıkça sorulan sorular4
Is Subsequence algoritmasının zaman karmaşıklığı nedir?
İki işaretçili çözüm, O(n + m) zamanda çalışır; burada n ve m, s ve t dizelerinin uzunluklarıdır ve O(1) ek bellek kullanır. Uygulamada döngü en fazla m adımdan sonra durur. Önek tablosu O(n × m) zaman alır.
Is Subsequence için açgözlü iki işaretçi yaklaşımı neden işe yarar?
s içindeki bir harfi t içinde mümkün olan en erken yerde eşleştirmek, t'nin geri kalanını kalan harfler için mümkün olduğunca uzun bırakır. Daha sonraki bir kopyayı kullanan herhangi bir yerleştirme, sıralamayı bozmadan daha erken olanı kullanacak şekilde değiştirilebilir; dolayısıyla herhangi bir yerleştirme varsa, açgözlü yöntem onu bulur.
Aynı t'ye karşı birçok diziyi hızlıca nasıl kontrol edersiniz?
t'yi bir kez hazırla: her harf için, göründüğü indekslerin sıralı listesini sakla. s[i]'yi yerleştirmek için, o harfin listesinde önceki eşleşmeden sonraki ilk indeksi ikili aramayla bul. Böylece her kontrol O(m) yerine O(n log m) maliyetine sahip olur.
Bir alt dizi ile bir alt dizge arasındaki fark nedir?
Bir alt dize, art arda gelen harflerden oluşan bir bloktur; alt dizi ise sıra aynı kaldığı sürece harfleri atlayabilir. ace, abcde dizisinin bir alt dizisidir ancak alt dizesi değildir. Her alt dize bir alt dizidir, ancak tersi doğru değildir.
Benzer problemler
Aynı fikirleri kullanan problemler. İki üçünü çözmek bir kalıbı kalıcı hale getirir.
Python
def isSubsequence(s, t):
# Kodu buraya yazınDurum 1
Durum 2
Durum 3
Girdi
s = "ace" t = "abcde"
Beklenen
true