同形部分文字列があるかどうかを確認します


12

この質問は、単語が同形かどうかをチェックする拡張機能で あり、その最初の部分をコピーして同形の定義を提供します。

2つの単語が同じ文字の繰り返しパターンを持っている場合、2つの単語は同形です。たとえば、両方ESTATEとDUELEDパターンを持っていますabcdca

ESTATE
DUELED

abcdca

文字1と6は同じであるため、文字3と5は同じであり、それ以上は何もありません。これは、単語が置換暗号によって関連付けられていることも意味しますE <-> D, S <-> U, T <-> E, A <-> L。ここでは一致しています。

XがY以下の2つの文字列XとYが与えられた場合、タスクは、Xと同形であるYの部分文字列があるかどうかを判断することです。

入力: a..zA..Zからの2行の空でない文字列。1行に1文字列。これは標準入力から取得されます。

出力このようなものが存在する場合、最初の文字列と同形である2番目の文字列の部分文字列。それ以外の場合は、「No!」を出力します。

ルールコードは、入力の全長で線形時間で実行する必要があります。

スコアスコアは、コードのバイト数です。少ないバイトが勝ちます。


入出力の例

adca
ddaddabdaabbcc

dabd

ヒント

少なくとも一つのない存在であることを、この問題に複雑、実質的に速く、線形時間ソリューション。


@AlexA。誰かが私に実行時間/複雑さを制限するなら、それはコードチャレンジであるべきだと言ったと思う。もちろん、それが間違っている場合は、それを変更させていただきます。

7
ランタイムがルールによって制限され、スコアリングに影響しない場合、code-golfはcode-challengeよりも適しています。
— デニス

線形時間は、O(mxn)やO(mx(nm))ではなくO(m + n)である必要があることを意味します。m、nは最初と2番目の文字列の長さですか?
— 一部のユーザー

@someuserはい、これはO(m + n)を意味します。

1
@BetaDecay「XがYより長くない2つの文字列XとYが与えられた場合、タスクはXと同型であるYの部分文字列があるかどうかを判断することです」を参照してください。

回答:


8

Python 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)

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!'

このアルゴリズムは、KMPのバリエーションであり、文字一致のインデックスベースのテストを使用しています。基本的な考え方は、位置で不一致が発生した場合、プレフィックスのに同形X[i]でX[:i]ある最長のサフィックスに従って、一致する次の可能な場所にフォールバックできるということですX。

左から右に作業して、各文字にその文字の直前の出現までの距離に等しいインデックスを割り当てるか、以前に出現しない場合は現在の文字列プレフィックスの長さを取得します。例えば:

MISSISSIPPI
12313213913

2つの文字が一致するかどうかをテストするために、インデックスを比較し、現在の(サブ)文字列の長さより大きいインデックスに適切に調整します。

KMPアルゴリズムは、最初の文字で不一致を取得できないため、少し単純化されます。

このプログラムは、最初に一致したものがあればそれを出力します。一致した場合に終了するにはランタイムエラーを使用しますが、コードを簡単に変更して、数バイトのコストできれいに終了することができます。

注:インデックスの計算には、str.rfind(辞書を使用する以前のアプローチとは対照的に)を使用できますstr.rfindが、アルファベットの各文字に対して、最後から検索を開始する(これが唯一の正気の実装選択と思われる)と仮定して、線形の複雑さを保持できます、文字列の同じ部分を2回走査する必要がないため、(アルファベットのサイズ)*(文字列のサイズ)比較の上限があります。

ゴルフの過程でコードがかなり難読化されたため、ここでは少し読みやすい初期の(293バイト)ソリューションを示します。

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!'

このe関数は、文字の等価性をテストします。このexecステートメントはインデックスを割り当て、いくつかの変数の初期化を行います。最初のループXはフォールバック値を処理し、2番目のループは文字列検索を行います。

更新:これは、1バイトのコストで正常に終了するバージョンです。

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

python3を実行することでバイトを節約できると思います。r=raw_inputR =対inputプリント上の4バイトと括弧のみ3.コスト節約
— Maltysen

@Maltysenはコメントをありがとう。これを書いたとき、私は、Python 3を考慮していないが、コストと節約のためとして、あなたは、Python 3でインデントにスペースとタブを混在させることはできませんので、追加の2バイトのコストがある
— ミッチ・シュワルツ

@Maltysenはフォローアップするために、問題はタブではなくの括弧になりましたexec。
— ミッチシュワルツ

これは本当に素晴らしい答えです!今cjamでそれを見るのを楽しみにしています:)

6

Python 3、401バイト

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!")

これはまだほとんど手付かずですが、うまくいくと思います。コアアルゴリズムはKMPに加えて、アルファベットのサイズの階乗である追加の因子です(アルファベットは一定なので、これで問題ありません)。言い換えれば、これは完全に非実用的な線形アルゴリズムの1つである必要があります。

分析に役立ついくつかの注釈を次に示します。

# 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!")

テストのためsに、より小さいアルファベットに置き換えることができますstring.ascii_letters。


2

APL(Dyalog)、32バイト

これは、Xを左引数として、Yを右引数として使用する中置関数です。

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

オンラインでお試しください!

{… } 匿名のラムダ。ここで⍺および⍵は引数(XおよびY)を表します

 ⍳⍨⍺ ɩ NDEX自分撮りXの(ɩ XにおけるXの要素の最初の発生のndices)

 ⊂ そのパターン全体を検索できるように囲みます

 (… )⍳ ɩで最初に出現したndex

  ≢⍺ Xの集計(長さ)

  ⍵,/⍨ そのサイズのYのすべての部分文字列(lit.それらの連結削減、ただしそれはノーオペレーションです)

  s← 格納s(s ubstrings の場合)

  ⍳⍨¨ ɩそれらのそれぞれのndex selfie

 これで最初のパターンのインデックス、または一致が見つからなかった場合は1 +パターンの数が得られます

 (… )⊃⍨ そのインデックスを使用して選択します…

  ⊂'No!' 囲まれた文字列(単一の要素として機能するように)

  s, を先頭に付けた s

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.