共産的な部分文字列の正規化


13

長さKのストリングTがストリングSK回以上現れるなら、それは潜在的に共産的です。例えば、でそれが現れるため、潜在的に共産主義で2回と長さである2。これらの部分文字列は重複できないことに注意してください。1010/10

共産変換は、この文字列かかり一つでTを、各キャラクタが移動するT iは、Tをするの発生TにおけるS。したがって、前の例では、共産主義の変換は次のようになり1/0ます。10置換の最初の文字が10最初に10検出され、02回目に検出されます。

共産正規化は、全てのそのようなストリングとる関数であるTK ≥2及び実行共産変換をそれらに。

アルゴリズムの詳細:

  1. 最初に最長の有効な文字列Tで 共産主義の変換を実行します。Tの最初の出現を優先します。
  2. 次に、次に長い文字列で共産主義的な変換を実行し、次に次に長い文字列で...などを実行します。
  3. そのような文字列が文字列に存在しなくなるまで繰り返します。

テストケースの「Hello、Hello」の例などの一部の文字列は、2つの異なる方法で解釈できることに注意してください。あなたは使用することができるellためにTが、あなたにも使用することができますllo。この場合、コードはいずれかのオプションを選択できます。示されているテストケースではを使用lloしていますが、異なる有効な出力が得られる場合があります。


あなたの仕事は、共産主義の正規化を実装することです。入力は、印刷可能なASCII文字(0x20〜0x7E、ティルドまでのスペース)のみで構成されます。このタスクを解決するプログラムまたは関数を作成できます。入力は、STDINからの行、文字列/文字配列引数、ARGVからの引数などとして取得できます。

テストケース

'123' -> '123'
'111' -> '111'
'1111' -> '11'
'ABAB' -> 'AB'
'111111111' -> '111'
'asdasdasd' -> 'asd'
'10/10' -> '1/0'
'100/100+100' -> '1/0+0'
'   +   +   ' -> ' + '
'Hello, hello, dear fellow!' -> 'Hel he, dear feow!' OR 'Heo hl, dear flow!'
'11122333/11122333/11122333' -> '112/13' OR '132/23'

'ababab1ababab' -> 'a1bab'
'1ab2ab3ab4ab5ab6' -> '1a2b3a4b5ab6'

テストケースを作成しました

形式は'string', 'substring'、置換の各ステップでです。交換されたビットは括弧で囲まれています。

'11[122]333/11[122]333/11[122]333', '122'
'111[333]/112[333]/112[333]', '333'
'1113/11[23]/11[23]', '23'
'11[13]/112/1[13]', '13'
'1[11]/[11]2/13', '11'
'1[/1]12[/1]3', '/1'
'112/13', ''

別のテストケース:

'Hello, hello, dear fellow!', 'llo'
'Hel, hel, dear feow!', 'l,'
'Hel he, dear feow!', ''

参照コード(Python)

これは、アルゴリズムを視覚化するのに役立ちます。

#!/usr/bin/env python

import re

def repeater(string):
    def repeating_substring(substring):
        return (string.count(substring) == len(substring)) and string.count(substring) > 1

    return repeating_substring

def get_substrings(string):
    j = 1
    a = set()
    while True:
        for i in range(len(string) - j+1):
            a.add(string[i:i+j])
        if j == len(string):
            break
        j += 1
    return list(a)

def replace_each_instance(string, substring):
    assert `string`+',', `substring`
    for i in substring:
        string = re.sub(re.escape(substring), i, string, 1)

    return string


def main(s):
    repeats = repeater(s)
    repeating_substr = filter(repeater(s), get_substrings(s))

    while repeating_substr:
        repeating_substr.sort(lambda x,y: cmp(len(y), len(x)))
        s = replace_each_instance(s, repeating_substr[0])
        repeating_substr = filter(repeater(s), get_substrings(s))

    return s

assert main('123') == '123'
assert main('111') == '111'
assert main('1111') == '11'
assert main('ABAB') == 'AB'
assert main('111111111') == '111'
assert main('asdasdasd') == 'asd'
assert main('10/10') == '1/0'
assert main('100/100+100') == '1/0+0'
assert main('   +   +   ') == ' + '
assert main('Hello, hello, dear fellow!') == 'Hel he, dear feow!'
assert main('11122333/11122333/11122333') == '112/13'

このチャレンジの元のアイデアを投稿してくれた@ ConorO'Brienに感謝します。


テストケース:ababab1ababab1ab2ab3ab4ab5ab6
Zgarb

なぜ変化がないのですか?ab両方の文字列で少なくとも2回発生します。
ズガーブ

@Zgarbは私のテスターが悪いようです。後で修正します。ただし、テストケースを手動で修正します。
Rɪᴋᴇʀ

回答:


2

Pyth、22バイト

u.xse.iLcGdf>cGTlTt#.:

テストスイート

プログラムが何をしているかを実際に確認するには、これをチェックしてください:

内部

特に、プログラムは、最も長い置換の最後に発生する置換を常に使用します。

説明:

u.xse.iLcGdf>cGTlTt#.:
u.xse.iLcGdf>cGTlTt#.:G)GQ    Implicit
u                        Q    Starting with the input, repeat the following
                              until a fixed point is reached.
                    .:G)      Construct all substrings of the current value
                              ordered smallest to largest, front to back.
                  t#          Filter on having more than 1 element.
                              These are the eligible substrings.
           f                  Filter these substrings on
             cGT              Chop the current value on the substring,
            >   lT            Then remove the first len(substring) pieces.
                              The result is nonempty if the substring is
                              one we're looking for. 
                              Chopping gives nonoverlapping occurrences.
     .iL                      Interlace the substrings with
        cGd                   Chop the current value on that substring
   se                         Take the final result, make it a string.
 .x                     G     If there weren't any, the above throws an error,
                              So keep the current value to halt.

4

JavaScript(ES6)、121バイト

f=(s,j=2,o,m=s.match(`(.{${j}})(.*\\1){${(j-1)}}`))=>m?f(s,j+1,s.split(m[1]).map((e,i)=>e+(m[1][i]||'')).join``):o?f(o):s

パターンを再帰的に一致させます:

(.{2})(.*\1){1}  //2 characters, repeated 1 time 
(.{3})(.*\1){2}  //3 characters, repeated 2 times 
(.{4})(.*\1){3}  //4 characters, repeated 3 times 
etc.

…パターンが見つからなくなるまで。(これにより、最も長い文字列が最初に処理されることが保証されます。)

次に、一致で分割し、一致の各文字に参加することにより、最後に見つかったパターンで「共産主義の変換」を実行します。(mapこの目的のために使用されjoinます。悪くてもコールバックは行われません。)

共産主義的でなくなるまで、この新しい文字列を最終的に再帰します。

テストケース:


1

クリーン420 ... 368バイト

import StdEnv,StdLib
l=length
%q=any((==)q)
?_[]=[]
?a[(y,x):b]|isPrefixOf a[x:map snd b]=[y: ?a(drop(l a-1)b)]= ?a b
$s=sortBy(\a b=l a>l b)(flatten[[b: $a]\\(a,b)<-map((flip splitAt)s)[0..l s-1]])
f s#i=zip2[0..]s
#r=filter(\b=l(?b i)>=l b&&l b>1)($s)
|r>[]#h=hd r
#t=take(l h)(?h i)
=f[if(%n t)(h!!hd(elemIndices n t))c\\(n,c)<-i|not(%n[u+v\\u<-t,v<-[1..l h-1]])]=s

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


この答えは無効です。こちらをご覧ください。変更する必要があります。テストケースを参照してください。
Rɪᴋᴇʀ

@Rikerは、リファレンスソリューションの直接ポートであるため、興味深いものです。修正されるまで削除します。
18年

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