Bir izomorf alt dizesi olup olmadığını kontrol edin


12

Bu soru Check kelimelerinin izomorf olup olmadığını kontrol etmenin bir uzantısıdır ve izomorf tanımını vermek için ilk kısmını kopyalar.

İki kelime , aynı harf tekrarlama örüntüsüne sahiplerse izomorflardır . Örneğin, her ikisi de ESTATEve DUELEDdesen varabcdca

ESTATE
DUELED

abcdca

çünkü 1 ve 6 harfleri aynıdır, 3 ve 5 harfleri aynıdır ve başka bir şey yoktur. Bu aynı zamanda kelimelerin bir ikame şifresi ile, burada eşleşmeyle ilişkili olduğu anlamına gelir E <-> D, S <-> U, T <-> E, A <-> L.

İki X ve Y dizesi verildiğinde, X, Y'den daha uzun değil, görev, X ile bir izomorf olan Y'nin bir alt dizisi olup olmadığını belirlemektir.

Girdi: Satır başına bir dize olan ..zA..Z'den boş olmayan iki harf dizesi. Bu standart girdiden gelecektir.

Çıktı Böyle bir şey varsa, ilk dizeyle izomorf olan ikinci dizenin bir alt dizesi. Aksi takdirde "Hayır!"

Kurallar Kodunuz, girdinin toplam uzunluğunda doğrusal sürede çalışmalıdır.

Puan Puanınız kodunuzdaki bayt sayısıdır. En az bayt kazanır.


Örnek giriş ve çıkış

adca
ddaddabdaabbcc

dabd

İpucu

Değil bir en azından yoktur o pratik olarak hızlı karmaşık ve bu soruna doğrusal zaman çözüm.


@AlexA. Sanırım birisi bana çalışma süresi / karmaşıklığı kısıtlarsanız, o zaman kod meydan okuma gerektiğini söyledi. Tabii ki bu yanlışsa değiştirdiğim için mutluyum.

7
Çalışma süresi bir kuralla sınırlandırılmışsa ve puanlamayı etkilemiyorsa, kod golfü kod meydan okumasından daha uygundur.
Dennis

doğrusal zaman, O (m + n) ve O (mxn) veya O (mx (nm)) olması gerektiği anlamına gelir; burada m, n, birinci ve 2. telin uzunluğu mu?
bazı kullanıcılar

@someuser Evet, O (m + n) anlamına gelir.

1
@BetaDecay Bkz. "X, Y'den uzun olmayan iki X ve Y dizesi verildiğinde görev, X ile bir izomorf olan Y'nin bir alt dizesi olup olmadığını belirlemektir."

Yanıtlar:


8

Piton 2, 338 326 323 321 310 306 297 293 290 289 280 279 266 264 259 237 230 229 226 223 222 220 219 217 ( 260 238 231 228 225 223 221 220 218 0 çıkış durumu ile)

exec'''s=raw_input()
S=[M-s.rfind(c,0,M)for M,c in enumerate(s)]
k=0
j=x=%s
while k<=M+x:
 if S[k]>j<W[j]or S[k]==W[j]:
    k+=1;j+=1;T+=[j]
    if j-L>x:print s[k-j:k];z
 else:j=T[j]
'''*2%('-1;T=[0];W=S;L=M',0)
print'No!'

Algoritma, karakter eşleme için dizin tabanlı bir test kullanan bir KMP varyasyonudur. Temel fikir, eğer pozisyonda bir uyumsuzluk X[i]alırsak, o zaman X[:i]bir önek için izomorfik olan en uzun ekine göre bir maç için bir sonraki olası yere geri dönebiliriz X.

Soldan sağa doğru çalışarak, her karaktere o karakterin en son önceki oluşumuna olan mesafeye eşit bir dizin atarız veya daha önce bir oluşum yoksa, geçerli dize önekinin uzunluğunu alırız. Örneğin:

MISSISSIPPI
12313213913

İki karakterin eşleşip eşleşmediğini test etmek için, mevcut (alt) dizenin uzunluğundan daha büyük dizinler için uygun şekilde ayarlayarak dizinleri karşılaştırırız.

KMP algoritması biraz basitleşir, çünkü ilk karakterde uyumsuzluk elde edemeyiz.

Bu program varsa ilk eşleşmeyi çıkarır. Bir eşleşme durumunda çıkmak için bir çalışma zamanı hatası kullanıyorum, ancak kod kolayca bazı baytlar pahasına temiz çıkmak için değiştirilebilir.

Not: Hesaplama indeksleri için, str.rfind(sözlük kullanarak önceki yaklaşımımın aksine) ve str.rfindalfabetikteki her karakter için sondan aramaya başladığını varsayarak (tek aklı başında uygulama seçeneği gibi görünüyor ) hala doğrusal karmaşıklığa sahibiz. , asla dizenin aynı kısmını iki kez geçmemiz gerekmediği için (alfabe boyutu) * (dize boyutu) karşılaştırmalarının bir üst sınırı vardır.

Golf sırasında kod oldukça gizlendiğinden, okunması biraz daha kolay olan daha eski (293 bayt) bir çözüm var:

e=lambda a:a>i<W[i]or a==W[i]
exec('s=raw_input();S=[];p={};M=i=0\nfor c in s:S+=[M-p.get(c,-1)];p[c]=M;M+=1\nW=S;L=M;'*2)[:-9]
T=[0]*L
k=1
while~k+L:
 if e(W[k]):i+=1;k+=1;T[k]=i
 else:i=T[i]
m=i=0
while m+i<M:
 if e(S[m+i]):
    if~-L==i:print s[m:m+L];z
    i+=1
 else:m+=i-T[i];i=T[i]
print'No!'

eFonksiyon testleri karakterlerin eşitlik gösteren. execDeyim indeksleri atar ve bazı değişken alıştırmalarını yapar. İlk döngü Xgeri dönüş değerlerini işler ve ikinci döngü dize aramasını yapar.

Güncelleme: İşte bir bayt pahasına temiz bir şekilde çıkan bir sürüm:

r='No!'
exec'''s=raw_input()
S=[M-s.rfind(c,0,M)for M,c in enumerate(s)]
k=0
j=x=%s
while k<=M+x:
 if S[k]>j<W[j]or S[k]==W[j]:
    k+=1;j+=1;T+=[j]
    if j-L>x:r=k=s[k-j:k]
 else:j=T[j]
'''*2%('-1;T=[0];W=S;L=M',0)
print r

Bence python3 yaparak bir bayt kaydedebilirsiniz. r=raw_inputvs. r = input4 bayt kurtardı ve
baskıdaki

@Maltysen yorum için teşekkürler. Bunu yazarken Python 3'ü düşünmedim, ancak maliyet ve tasarruf açısından, Python 3'teki girinti için boşlukları ve sekmeleri karıştıramayacağınız için 2 baytlık ek bir maliyet var
Mitch Schwartz

@Maltysen sadece takip etmek için, sorun artık sekmeler değil, parantez için exec.
Mitch Schwartz

Bu gerçekten harika bir cevap! Şimdi cjam görmek için sabırsızlanıyoruz :)

6

Python 3, 401 bayt

import string,itertools
X=input()
Y=input()
x=len(X)
t=[-1]+[0]*~-x
j=2
c=0
while j<x:
 if X[j-1]==X[c]:c+=1;t[j]=c;j+=1
 elif c>0:c=t[c]
 else:t[j]=0;j+=1
s=string.ascii_letters
*b,=map(s.find,X)
for p in itertools.permutations(s):
 m=i=0
 while m+i<len(Y):
  if p[b[i]]==Y[m+i]:
   if~-x==i:print(Y[m:m+x]);exit()
   else:i+=1
  else:
   if-1<t[i]:m+=i-t[i];i=t[i]
   else:i=0;m+=1
else:print("No!")

Bu hala çoğunlukla çözülmemiş, ama bence işe yaramalı. Çekirdek algoritma KMP'dir , artı alfabe boyutunda faktöryel olan ek bir faktördür (bu, alfabe sabit olduğu için iyidir). Başka bir deyişle, bu tamamen pratik olmayan bir doğrusal algoritmadır / olmalıdır.

Analize yardımcı olacak birkaç ek açıklama:

# KMP failure table for the substring, O(n)
t=[-1]+[0]*~-x
j=2
c=0
while j<x:
 if X[j-1]==X[c]:c+=1;t[j]=c;j+=1
 elif c>0:c=t[c]
 else:t[j]=0;j+=1

# Convert each char to its index in a-zA-Z, O(alphabet * n)
s=string.ascii_letters
*b,=map(s.find,X)

# For every permutation of letters..., O(alphabet!)
for p in itertools.permutations(s):
 # Run KMP, O(n)
 m=i=0
 while m+i<len(Y):
  if p[b[i]]==Y[m+i]:
   if~-x==i:print(Y[m:m+x]);exit()
   else:i+=1
  else:
   if-1<t[i]:m+=i-t[i];i=t[i]
   else:i=0;m+=1
else:print("No!")

Test için, yerine sdaha küçük bir alfabe kullanabilirsiniz string.ascii_letters.


2

APL (Dyalog) , 32 bayt

Bu, X'i sol argüman ve Y'yi sağ argüman olarak alan bir infix işlevidir.

{(s,⊂'No!')⊃⍨(⍳⍨¨s←⍵,/⍨≢⍺)⍳⊂⍳⍨⍺}

Çevrimiçi deneyin!

{} İsimsiz lambda nerede ve argümanları temsil eder (X ve Y)

⍳⍨⍺ɩ nDex selfie'si X ( ɩ X X elemanlarının ilk geçtiği ndices)

 tüm deseni arayabilmemiz için

(… İlk ortaya )⍳çıkışında ndex…

  ≢⍺ X'in çetelesi (uzunluğu)

  ⍵,/⍨ Y boyutundaki tüm alt dizeler (bunların yan yana birleştirilmesi azalması, ancak bu işlem yapılmaz)

  s← mağazada s( s ubstrings için)

  ⍳⍨¨Bunların her birinin selfie ndex selfie

 şimdi ilk paternin dizinine sahibiz veya 1 + eşleşme bulunamazsa patern sayısı

()⊃⍨ Seçim yapmak için bu dizini kullanın…

  ⊂'No!' ekli dize (tek bir öğe olarak işlev görmesi için)

  s, ile eklenmiş s

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.