文字列のローカル期間


20

ローカル期間

空でない文字列sを取得します。ローカル周期Sインデックスでは、iが最小の正の整数n個毎ように0≤K <N 、我々は、S [I + K] = S [I-N + K]両側が定義されるたびに。または、連結wwsの隣に配置され、wの2番目のコピーがsのインデックスiで始まる場合、2つの文字列は重複する場所で一致するように、空でない文字列wの最小長です。

例として、(0から始まる)インデックス2 でs = "abaabbab"のローカル周期を計算してみましょう。

  • n = 1を試してください:s [2 + 0]≠s [2-1 + 0]なので、この選択は正しくありません。
  • n = 2を試してください:それからs [2 + 0] = s [2-2 + 0]s [2 + 1]≠s [2-2 + 1]なので、これも正しくありません。
  • n = 3を試してください:s [2 + 0-3]は定義されません、s [2 + 1] = s [2-3 + 1]およびs [2 + 2] = s [2-3 + 2]。したがって、ローカル期間は3です。

次に、2番目の定義を使用したローカル期間の視覚化を示します。わかりやすくするために、wの2つのコピーの間にセミコロンを追加します。

index      a b a a b b a b      period
 0       a;a                     1
 1       b a;b a                 2
 2       a a b;a a b             3
 3             a;a               1
 4     b b a b a a;b b a b a a   6
 5                 b;b           1
 6               a b b;a b b     3
 7                   b a;b a     2

wは必ずしもsの部分文字列ではないことに注意してください。これは、インデックス4の場合に発生します。

タスク

入力は、小文字のASCII 文字空でない文字列です。必要に応じて、文字のリストとして使用できます。出力は、各インデックスのsのローカル期間を含むリストになります。上記の例では、正しい出力は[1,2,3,1,6,1,3,2]になります。

各言語の最低バイト数が優先されます。標準の規則が適用されます。

テストケース

a -> [1]
hi -> [1, 2]
www -> [1, 1, 1]
xcxccxc -> [1, 2, 2, 5, 1, 3, 2]
abcbacb -> [1, 4, 7, 7, 7, 3, 3]
nininini -> [1, 2, 2, 2, 2, 2, 2, 2]
abaabbab -> [1, 2, 3, 1, 6, 1, 3, 2]
woppwoppw -> [1, 4, 4, 1, 4, 4, 4, 1, 4]
qwertyuiop -> [1, 10, 10, 10, 10, 10, 10, 10, 10, 10]
deededeededede -> [1, 3, 1, 5, 2, 2, 5, 1, 12, 2, 2, 2, 2, 2]
abababcabababcababcabababcaba -> [1, 2, 2, 2, 2, 7, 7, 7, 7, 2, 2, 2, 19, 19, 5, 5, 2, 5, 5, 12, 12, 2, 2, 2, 7, 7, 5, 5, 2]

@Arnauld sと同じ長さwを常に見つけることができます。の場合、wはの回転バージョンになります。インデックス4の例を参照してください。wは必ずしもsのサブストリングではありません。qwertyuiopqwertyuiop
ズガルブ

それは理にかなっている。チャレンジを誤解しています。
アーナウルド

線形時間ソリューションの想像上のボーナス!(他の誰かが本当の賞金を提供するかもしれないので、試してください)
-user202729

本当にきちんとした挑戦ですが、2つのキャラクターの間の各位置のローカル期間を定義する方が理にかなっているのでしょうか(;例のどこにでも)。それは主要な1を取り除くでしょう
マーティン・エンダー

@MartinEnderこれは概念的にはきれいですが、この定義により、文字列をループすることで出力を生成しやすくなり、出力は空になりません。
-Zgarb

回答:


4

網膜89 86バイト

.
$`¶$<'¶
/(^|.+)¶.+/_(Lw$`^(.+)?(.*)(.+)?¶(?(1)|(.*))\2(?(3)$)
$2$3$4
G`.
%C`.
N`
0G`

オンラインでお試しください!編集:@MartinEnderのおかげで3バイトを保存しました。説明:

.
$`¶$<'¶

入力を各文字で分割し、プレフィックスの行とプレフィックスの接尾辞の行を作成します。

/(^|.+)¶.+/_(

結果の各ペアでスクリプトの残りを実行します。

Lw$`^(.+)?(.*)(.+)?¶(?(1)|(.*))\2(?(3)$)
$2$3$4

重複するすべての一致を検索し、結果をリストします。(下記参照。)

G`.

空の一致を破棄します。

%C`.

各マッチの長さを取ります。

N`

数値順に並べ替えます。

0G`

最小を取ります。

一致は、プレフィックスとサフィックスを3つの部分に分割することで機能します。考慮すべき4つの有効なケースがあります。

AB|BC   B matches B to the left and B to the right
B|ABC   AB matches [A]B to the left and AB to the right
ABC|B   BC matches BC to the left and B[C] to the right
BC|AB   ABC matches [A]BC to the left and AB[C] to the right

したがって、正規表現では、AとCが一度に片側でのみ一致することが許可されます。


$&$'はに等しく、$<'行の長さの計算はで短くなり%C`.ます。tio.run/##K0otycxLNPz/X49LJeHQNhUb9UPbuPQ14mr0tDUPbdPT1o/...
マーティン・エンダー

4

Javaの8、167の 154 152バイト

s->{int l=s.length,r[]=new int[l],i=0,n,k;for(;i<l;r[i++]=n)n:for(n=0;;){for(k=++n;k-->0;)if(i+k<l&i+k>=n&&s[i+k]!=s[i-n+k])continue n;break;}return r;}

@ceilingcatのおかげで-2バイト。

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

説明:

s->{                          // Method with char-array parameter and int-array return-type
  int l=s.length,             //  Length of the input-array
      r[]=new int[l],         //  Result-array of the same size 
      i=0,n,k;                //  Integers `i`, `n`, and `k` as defined in the challenge
  for(;i<l;                   //  Loop `i` in the range [0, `l`):
      r[i++]=n)               //    After every iteration: Add `n` to the array
    n:for(n=0;;){             //   Inner loop `n` from 0 upwards indefinitely
      for(k=++n;k-->0;)       //    Inner loop `k` in the range [`n`, 0]:
                              //    (by first increasing `n` by 1 with `++n`)
        if(i+k<l&i+k>=n)      //     If `i+k` and `i-n+k` are both within bounds,
           &&s[i+k]!=s[i-n+k])//     and if `s[i+k]` is not equal to `s[i-n+k]`:
          continue n;         //      Continue loop `n`
                              //    If we haven't encountered the `continue n` in loop `k`:
      break;}                 //     Break loop `n`
  return r;}                  //  Return the result

1

JavaScript(ES6)、84バイト

入力を文字の配列として受け取ります。

s=>s.map((_,i)=>s.some(_=>s.every(_=>k<j|!s[k]|s[k-j]==s[k++]|k-i>j,++j,k=i),j=0)*j)

テストケース


文字の配列を使用できるかどうかはわかりませんが、1文字の文字列だけではないのですか?
エリックアウトゴルファー

@EriktheOutgolfer JSには文字タイプがないので、はい:技術的には1文字の文字列の配列です。私の理解では、もし文字列のように鳴るとすれば、それは文字列だということです。(これに関するメタ投稿がありますが、より関連性の高いものが存在する可能性があります-または実際に私の仮定と矛盾するものです。)
Arnauld

1
または、言い換えると、これは、OPによって明示的に許可されたJS の文字のリストに到達できる範囲に近いものです。
アーナルド

1

ルビー104 102バイト

->s{l=s.size-1
(0..l).map{|i|n=0
loop{n+=1
(n-i..l-i).all?{|k|k<0||k>=n||s[i+k]==s[i-n+k]}&&break}
n}}

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

文字列を受け取り、配列を返すラムダ。

-2バイト:インデックスバインドガードを使用した範囲エンドポイントのスワップ

ゴルフをしていない:

->s{
  l=s.size-1                # l is the maximum valid index into s
  (0..l).map{ |i|           # i is the current index
    n=0                     # n is the period being tested
    loop{                   # Repeat forever:
      n+=1                  # Increment n
      (n-i..l-i).all?{ |k|  # If for all k where i+k and i-n+k are valid indexes into s
        k<0 || k>=n ||      #   We need not consider k OR
          s[i+k]==s[i-n+k]  #   The characters at the relevant indexes match
      } && break            # Then stop repeating
    }
  n                         # Map this index i to the first valid n
  }
}

1

Japt33 32バイト

@Shaggyのおかげで1バイト節約

¬Ë@¯E f'$iUtED ú.D r."($&|^)"}aÄ

オンラインでテストしてください!

説明

¬Ë@¯E f'$iUtED ú.D r."($&|^)"}aÄ   Implicit: U = input string
¬Ë                                 Split the input into chars, and map each index E to
  @                          }aÄ     the smallest positive integer D where
   ¯E                                  the first E chars of U
      f                                matches the regex formed by
          UtED                         taking D chars of U from index E,
                ú.D                     padding to length D with periods,
                    r."($&|^)"          replacing each char C with "(C|^)",
        '$i                             and placing a '$' at the very end.

私が最初に考えたのは、JSの回答のように、左側の部分文字列の各文字と右側の部分文字列の対応する文字を比較することだけでした。ただし、インデックスが負の値または大きすぎる場合、文字を取得するJaptのメソッドは文字列のもう一方の端にラップするだけなので、それは機能しません。

代わりに、私のソリューションは2番目のサブストリングから正規表現を構築し、最初のサブストリングでテストします。テストケースの5番目の項目をabaabbab例としてみましょう。

abaabbab
    ^ split point -> abaa for testing regex, bbab for making regex

   slice  regex                              matches abaa
1. b      /(b|^)$/                           no
2. bb     /(b|^)(b|^)$/                      no
3. bba    /(b|^)(b|^)(a|^)$/                 no
4. bbab   /(b|^)(b|^)(a|^)(b|^)$/            no
5. bbab.  /(b|^)(b|^)(a|^)(b|^)(.|^)$/       no
6. bbab.. /(b|^)(b|^)(a|^)(b|^)(.|^)(.|^)$/  yes: /^^ab..$/

主なトリックは^、実際の文字が一致するまで、無限に一致できることです。これにより、正規表現の先頭からの任意の数の文字を無視することができ、残りはすべて連続して一致し、テスト文字列の最後で終了します。

これを非常にうまく説明したかどうかはわかりませんので、明確にしたいもの、または説明する必要のあるものがあれば教えてください。



@シャギーありがとう、そのセミコロンは私を
悩ま

1

C(gcc)143 142 140 139 128 126 123バイト

  • バイトを保存しました。Golfed !b&&printfb||printf
  • Kevin Cruijssenのおかげで2バイト節約されました。配置をforジャグリングしてループ本体の括弧を削除しましたprintf
  • バイトを保存しました。Golfed b+=S[i+k]!=S[i-n+k]b|=S[i+k]-S[i-n+k]
  • 11バイトを保存しました。l=strlen(S)両方の文字列処理ループを、文字列の最後(nullバイト'\0')に達したときに中断するように調整する必要性を削除しました。
  • 2バイトを保存しました。Golfed i-n+k>~0i-n>~k
  • ceilingcatのおかげで3バイト節約されましたb||printf("|"),n++はと同等n+=b||printf("|")です。
i,b,k,n;f(char*S){for(i=~0;S[++i];)for(b=n=1;b;n+=b||printf("%d,",n))for(b=k=0;k<n&&S[i+k];k++)b|=n-i>k?0:S[i+k]-S[i-n+k];}

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


あなたは括弧を削除して入れて2つのバイトを保存することができますb||printf("%d,",n):forループ内でi,b,k,n,l;f(char*S){for(l=strlen(S),i=-1;++i<l;)for(b=n=1;b;b||printf("%d,",n),n++)for(b=k=0;k<n;k++)i+k<l&i-n+k>=0&&(b+=S[i+k]!=S[i-n+k]);} 140バイト
ケビンCruijssenを

@KevinCruijssenありがとうございます。
ジョナサンフレッチ

@ceilingcatありがとう。きちんとした同等性、その1つ。
ジョナサンフレッチ

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