特権部分文字列を検索


8

特権文字列

特権文字列のセットは、次のように再帰的に定義されます。

  • 長さが0または1のすべての文字列は特権付きです。
  • プレフィックスとしてとサフィックスとして1回ずつ、正確に2回出現sする短い特権文字列が存在する場合、少なくとも2 文字の長さの文字列が特権となります。重複する発生は、個別としてカウントされます。ts

たとえば、文字列aaaaaおよびabaは特権ですがab、そうでaabはありません。

入力

英数字の文字列。

出力

入力文字列のすべての特権付きサブ文字列(それぞれ1回だけ、任意の順序)。出力は、言語のネイティブ配列形式(またはそれに最も近いもの)で指定するか、1行に1つの部分文字列を出力できます。

楽しい事実

出力の文字列の数は常に正確ですlength(s) + 1source)。

ルール

機能と完全なプログラムの両方が許可されています。最も低いバイト数が優先され、標準の抜け穴は許可されません。

テストケース

これらは最初に長さ順に、次にアルファベット順にソートされますが、どのような順序でもかまいません。

"" -> [""]
"a" -> ["","a"]
"abc" -> ["","a","b","c"]
"abcaaabccaba" -> ["","a","b","c","aa","cc","aaa","aba","abca","abcca","bccab","bcaaab","caaabc"]
"1010010110101010001101" -> ["","0","1","00","11","000","010","101","0110","1001","01010","10001","10101","010010","101101","0101010","1010101","01011010","10100101","1010001101","1101010100011","00101101010100","011010101000110"]
"CapsAndDigits111" -> ["","1","A","C","D","a","d","g","i","n","p","s","t","11","111","igi","sAndDigits"]

リーダーボード

これは、MartinBüttnerの好意による言語別のリーダーボードです。

回答が確実に表示されるようにするには、次のMarkdownテンプレートを使用して、見出しから回答を始めてください。

# Language Name, N bytes

N提出物のサイズはどこですか。スコアを向上させる場合、古いスコアを打ち消すことで見出しに残すことができます。例えば:

# Ruby, <s>104</s> <s>101</s> 96 bytes


出力はスペースで区切ることができますか、それとも改行で区切る必要がありますか?(印刷の場合)
Sp3000、2015

@ Sp3000改行にする必要があります。または、言語によって文字列の配列が出力されます。
Zgarb 2015

2
それで、あなたは私たちにあなたの特権文字列をチェックするように頼んでいるのですか?
imallett 2015

なぜそんなに長い定義なのか?「特権文字列とは、同じ記号で始まり、同じ記号で終わる文字列であり、その記号は、文字列の他のどこにも出現しない」と同等に書いていただけませんか?=)
Mints97、2015

1
@ Mints97短い文字列tは単一の記号ではない可能性があります。たとえば、aaaは特権文字列です。これはaa、接頭辞と接尾辞があり、2回しか出現しないためです。例として追加しました。
Zgarb 2015

回答:


4

.NET Regex、31バイト

(?=(((?<=(\3\2|)).+?(?<=\3))*))

文字列は\1、各一致でキャプチャされます。

説明

(?=                             # Lookahead. This makes it possible to catch overlapped
                                #   strings in \1.
    (                           # The captured group \1 for result.
        (                       # Match 0 or more occurrences.
            (?<=(\3\2|))        # Set \3 to the string from last \3 to the current position,
                                #   or an empty string for the first time.
            .+?(?<=\3)          # Match a shortest nonempty string so that the whole string
                                #   from the beginning to the current position ends with \3.
        )*
    )
)

5

CJam、33 45 39 38バイト

l_,,\f>{(0{:U2$>2$2$#):T<+UT+T}g;\;N}%

末尾の改行なしで印刷されているとしましょう。したがって、末尾の改行は空の部分文字列を意味します...

説明

l              " Read one line. ";
_,,            " Get an array of 0 to array length-1. ";
\f>            " Get all nonempty suffixes. ";
{              " For each suffix: ";
    (          " Extract the first character. Say the first character X and the rest Y. ";
    0          " Push U = 0. ";
    {          " Do: ";
        :U     " Set variable U. ";
        2$>    " Z = Y with first U characters removed. ";
        2$2$#  " Find X in Y, or return -1 if not found. ";
        ):T    " Increment and save it in T. ";
        <+     " Append the first T characters of Z to X. ";
        UT+    " U += T. ";
        T      " Push T. ";
    }g         " ...while T is nonzero. ";
    ;\;        " Discard U and Y. ";
    N          " Append a newline. ";
}%

4

Python 2、179 173 164バイト

exec"f=lambda s:len(s)<2or any(s[1:-1].count(s[:n])<(s[:n]==s[-n:])==f(s[:n])for n%s);g=lambda s:filter(f,{''}|{s[i:j+1]for i%sfor j%s})"%((" in range(len(s))",)*3)

現在かなりかさばります—どういうわけか、チェックと部分文字列の生成を組み合わせることができるかどうか疑問に思います...

ラムダfは基本的にはis_privileged()関数であり、3つの条件を1つの比較に結合します(部分文字列は特権があり、2回出現し、接尾辞と接頭辞です)。

拡張:

f=lambda s:len(s)<2or any(s[1:-1].count(s[:n])<(s[:n]==s[-n:])==f(s[:n])for n in range(len(s)))
g=lambda s:filter(f,{''}|{s[i:j+1]for i in range(len(s))for j in range(len(s))})

3

Python 3、131 129バイト

f=lambda s,p={''}:(len(s)<2or[f(s[1:]),f(s[:-1])]*any(s[:len(x)]==s[-len(x):]==x not in s[1:-1]for x in p))and p.add(s)or list(p)

これにより、権限のある部分文字列が再帰的に検出され、最短の文字列から始めて、セットに追加されます。次に、このセットは、より長いサブストリングに特権があるかどうかを判別するために使用されます。

残念ながら、これは使い捨ての機能です。これは対応する完全なプログラムです(145バイト):

p={''}
f=lambda s:(len(s)<2or[f(s[1:]),f(s[:-1])]*any(s[:len(x)]==s[-len(x):]==x not in s[1:-1]for x in p))and p.add(s)
f(input())
print(list(p))

3

Python、152 147 126116バイト

def n(s):
 w='';t=[w]
 for a in s:w+=a;t+=[w[w.rfind(w[-max(len(q)for q in t if w.endswith(q)):],0,-1):]]
 return t

リンク先の論文で示されているように、文字列のすべてのプレフィックスには、一意の特権付きサフィックスがあります。そのサフィックスは、の形式です。p·u·pここpで、は、プレフィックスのサフィックスである、以前に見つかった最も長い特権サブストリングです。(検索はの引数maxであり、実際pにはmaxよりも簡単だったため、の長さを検出しますlongest。)pが見つかると、接頭辞自体はp、接頭辞の最後から2番目の出現を検索することによって形成されrfindます。最後のキャラクター。pは以前に見つかったサフィックスなので、これでうまくいくことがわかります。(アルゴリズムのより厳密な証明は、論文から導き出すことができます。)

これは、上記で使用した2次 3次アルゴリズムの代わりに、サフィックスツリーを使用して線形時間で実装できると確信していますが、上記のプログラムはすべてのテストケースで確かに十分高速で、2000 a秒の文字列を処理します。私の(超高性能ではない)ラップトップで1秒弱。


2

Ruby、87

私はどこかに再帰的な正規表現の解決策があるように感じますが、私はそれらがあまり得意ではないので、ここに非常に遅くて長い再帰的な関数があります。

f=->s{s[/./]?(o=f[$']|f[s.chop];o.any?{|t|s[/^#{t}/]&&s[/.#{t}/]&&!$'[0]}&&o<<s;o):[s]}

アルゴリズムはgrcのアルゴリズムとほぼ同じですが、単一の文字を特殊なケースにしないことにより、速度が遅くなります(ただし短くなります)。単一文字の文字列は、空の文字列がプレフィックス、サフィックスとしてあり、他の場所がないため、特権があると見なすことができます。

ここでのもう1つの興味深いトリックは、$'Perlから継承された、最後に正規表現が一致した後に文字列の値を取得するマジック変数の使用です。これにより、文字列から最初の文字を切り取る簡単な方法が得られますが、のs[/./]代わりにを使用して設定することにより、これらの文字のほとんどすべてを取得できますs[0]。もう一度使用して、2番目の部分文字列の一致が文字列の最後で発生することを確認します。


1

J、92バイト

最長の入力に数秒かかります。

p文字列が(再帰で)特権があるかどうかをチェックし、sを使用してすべての部分文字列をチェックしpます。

   p=.1:`(+./@:(($:@>@{.*((2=+/)*1={:)@{.@=)@(<\))~i.@#)@.(1<#)
   s=.3 :'~.a:,,(<@#~p)\.\y'   

テスト:

   s 'CapsAndDigits111'
┌┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬───┬─┬──────────┬─┬──┬───┐
││C│a│p│s│A│n│d│D│i│g│igi│t│sAndDigits│1│11│111│
└┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴───┴─┴──────────┴─┴──┴───┘       

   input =. '';'a';'ab';'abc';'abcaaabccaba';'1010010110101010001101';'CapsAndDigits111'

   s each input
┌──┬────┬──────┬────────┬─────────────────────────────────────────────────────┬────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬────────────────────...
│┌┐│┌┬─┐│┌┬─┬─┐│┌┬─┬─┬─┐│┌┬─┬─┬─┬────┬──┬───┬──────┬──────┬──┬─────┬─────┬───┐│┌┬─┬─┬───┬───┬──┬────┬──────┬────────┬──┬────┬──────┬────────┬─────┬─────┬───────┬───────┬──────────────┬───┬─────┬─────────────┬───────────────┬──────────┐│┌┬─┬─┬─┬─┬─┬─┬─┬─┬─┬...
││││││a││││a│b││││a│b│c││││a│b│c│abca│aa│aaa│bcaaab│caaabc│cc│abcca│bccab│aba││││1│0│101│010│00│1001│010010│10100101│11│0110│101101│01011010│10101│01010│1010101│0101010│00101101010100│000│10001│1101010100011│011010101000110│1010001101││││C│a│p│s│A│n│d│D│i│...
│└┘│└┴─┘│└┴─┴─┘│└┴─┴─┴─┘│└┴─┴─┴─┴────┴──┴───┴──────┴──────┴──┴─────┴─────┴───┘│└┴─┴─┴───┴───┴──┴────┴──────┴────────┴──┴────┴──────┴────────┴─────┴─────┴───────┴───────┴──────────────┴───┴─────┴─────────────┴───────────────┴──────────┘│└┴─┴─┴─┴─┴─┴─┴─┴─┴─┴...
└──┴────┴──────┴────────┴─────────────────────────────────────────────────────┴────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴────────────────────...

   #@s each input NB. number of strings in outputs
┌─┬─┬─┬─┬──┬──┬──┐
│1│2│3│4│13│23│17│
└─┴─┴─┴─┴──┴──┴──┘

   # each input NB. input lengths
┌─┬─┬─┬─┬──┬──┬──┐
│0│1│2│3│12│22│16│
└─┴─┴─┴─┴──┴──┴──┘

1

JavaScript(ES6)195

P関数は、文字列が特権を持っていることを再帰的に検証します。
F関数は、指定された文字列に含まれるすべての部分文字列を試行します。見つかった文字列は、重複を避けるためにハッシュテーブルのキーとして保存されます。
最後に、キーが出力として返されます。

F=a=>{
  P=(s,l=s.length,r=l<2,j=1)=>{
    for(;!r&&j<l;j++)s.indexOf(x=s.slice(0,j),1)+j-l||(r=P(x));
      return r
  };      
  for(o={'':l=i=0};a[i+l]||a[i=0,++l];)
    if(P(p=a.slice(i++,i+l)))
      o[p]=0;
  return[a for(a in o)]
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.