Periode string lokal


20

Periode lokal

Ambil string yang tidak kosong s . The periode lokal dari s pada indeks i adalah yang terkecil bilangan bulat positif n sehingga untuk setiap 0 ≤ k <n ini, kami memiliki s [i + k] = s [i-n + k] setiap kali kedua sisi didefinisikan. Atau, itu adalah panjang minimum dari string kosong yang w sehingga jika gabungan ww ditempatkan di sebelah s sehingga salinan kedua w dimulai pada indeks i dari s , maka dua string setuju di mana pun mereka tumpang tindih.

Sebagai contoh, mari kita hitung periode lokal s = "abaabbab" di indeks (berbasis-0) 2.

  • Coba n = 1 : lalu s [2 + 0] ≠ s [2-1 + 0] , jadi pilihan ini tidak benar.
  • Coba n = 2 : lalu s [2 + 0] = s [2-2 + 0] tetapi s [2 + 1] ≠ s [2-2 + 1] , jadi ini juga tidak benar.
  • Coba n = 3 : maka s [2 + 0-3] tidak didefinisikan, s [2 + 1] = s [2-3 + 1] dan s [2 + 2] = s [2-3 + 2] . Jadi periode lokal adalah 3.

Berikut adalah visualisasi periode lokal menggunakan definisi kedua, dengan titik koma ditambahkan di antara dua salinan w untuk kejelasan:

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

Perhatikan bahwa w tidak harus merupakan substring dari s . Ini terjadi di sini dalam kasus indeks-4.

Tugas

Masukan Anda adalah tak kosong serangkaian s karakter ASCII huruf kecil. Itu dapat diambil sebagai daftar karakter jika diinginkan. Output Anda akan menjadi daftar yang berisi periode lokal s pada setiap indeksnya. Dalam contoh di atas, output yang benar adalah [1,2,3,1,6,1,3,2] .

Hitungan byte terendah di setiap bahasa menang. Aturan standar berlaku.

Uji kasus

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 Anda selalu dapat menemukan w dengan panjang yang sama dengan s . Dalam kasus qwertyuiop, w akan menjadi versi yang diputar qwertyuiop. Lihat juga contoh pada indeks 4: w belum tentu merupakan substring dari s .
Zgarb

Itu masuk akal. Saya salah membaca tantangan.
Arnauld

Bonus imajiner untuk solusi waktu linier! (orang lain mungkin menawarkan hadiah nyata, jadi teruslah mencoba)
user202729

Benar-benar tantangan yang rapi, tapi saya ingin tahu apakah akan lebih masuk akal untuk menentukan periode lokal setiap posisi antara dua karakter (yaitu di mana pun ;dalam contoh Anda). Itu akan menyingkirkan pemimpin 1.
Martin Ender

@ MartinEnder Itu akan lebih bersih secara konseptual, tetapi definisi ini membuatnya lebih mudah untuk menghasilkan output dengan mengulangi string, dan output tidak akan kosong.
Zgarb

Jawaban:


4

Retina , 89 86 byte

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

Cobalah online! Sunting: Disimpan 3 byte berkat @MartinEnder. Penjelasan:

.
$`¶$<'¶

Pisahkan input di setiap karakter, buat sepasang garis, satu untuk awalan dan satu untuk akhiran awalan.

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

Jalankan sisa skrip pada setiap pasangan yang dihasilkan.

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

Temukan semua pertandingan yang tumpang tindih dan daftarkan hasilnya. (Lihat di bawah.)

G`.

Buang korek kosong.

%C`.

Ambil durasi setiap pertandingan.

N`

Sortir secara numerik.

0G`

Ambil yang terkecil.

Pencocokan bekerja dengan memisahkan awalan dan akhiran menjadi tiga bagian. Ada empat kasus yang valid untuk dipertimbangkan:

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

Karena itu regex hanya memungkinkan A dan C untuk mencocokkan satu sisi pada satu waktu.


$&$'sama dengan $<'dan panjang garis komputasi lebih pendek dengan %C`.. tio.run/##K0otycxLNPz/X49LJeHQNhUb9UPbuPQ14mr0tDUPbdPT1o/…
Martin Ender

4

Java 8, 167 154 152 byte

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;}

-2 byte terima kasih kepada @ceilingcat .

Cobalah online.

Penjelasan:

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 byte

Mengambil input sebagai array karakter.

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)

Uji kasus


Saya tidak yakin jika mengambil array karakter diperbolehkan, apakah Anda yakin itu bukan hanya string 1 karakter?
Erik the Outgolfer

@EriktheOutgolfer Tidak ada tipe karakter di JS, jadi ya: secara teknis ini adalah array string 1-karakter. Pemahaman saya adalah bahwa jika dukun seperti string, itu adalah string. (Berikut ini adalah meta pos tentang hal itu, tetapi yang lebih relevan mungkin ada - atau yang benar-benar bertentangan dengan asumsi saya.)
Arnauld

1
Atau dengan kata lain: ini sedekat yang bisa kita dapatkan dengan daftar karakter dalam JS, yang secara eksplisit diizinkan oleh OP.
Arnauld

1

Ruby , 104 102 byte

->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}}

Cobalah online!

Lambda menerima string dan mengembalikan array.

-2 byte: Tukar titik akhir jangkauan dengan penjaga terikat indeks

Tidak Terkumpul:

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

Japt , 33 32 byte

Disimpan 1 byte berkat @Shaggy

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

Uji secara online!

Penjelasan

¬Ë@¯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.

Pikiran pertama saya adalah membandingkan setiap karakter di substring kiri dengan karakter yang sesuai di substring kanan, seperti pada jawaban JS. Itu tidak akan berhasil, bagaimanapun, sebagai metode Japt untuk mendapatkan karakter hanya membungkus ke ujung string jika indeks negatif atau terlalu besar.

Sebagai gantinya, solusi saya membangun regex dari substring kedua dan mengujinya pada substring pertama. Mari kita ambil item ke-5 dalam test-case abaabbabsebagai contoh:

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..$/

Trik utama yang ^dapat dicocokkan tanpa batas, hingga karakter yang sebenarnya cocok. Ini memungkinkan kita mengabaikan sejumlah karakter dari awal regex, sambil memastikan bahwa sisanya semuanya dicocokkan secara berurutan, berakhir di akhir string uji.

Saya tidak yakin saya sudah menjelaskan ini dengan baik, jadi tolong beri tahu saya jika ada sesuatu yang ingin Anda klarifikasi, atau hal lain yang harus dijelaskan.



@Shaggy Terima kasih, koma itu menggangguku: P
ETHproduk

1

C (gcc) , 143 142 140 139 128 126 123 byte

  • Disimpan satu byte. Golf !b&&printfuntuk b||printf.
  • Disimpan dua byte berkat Kevin Cruijssen . Menghapus forkurung badan loop dengan menyulap printfpenempatan.
  • Disimpan satu byte. Golf b+=S[i+k]!=S[i-n+k]untuk b|=S[i+k]-S[i-n+k].
  • Disimpan sebelas byte. Menghilangkan kebutuhan l=strlen(S)dengan mengkondisikan kedua loop penanganan string agar putus saat mencapai ujung string (byte nol '\0').
  • Disimpan dua byte. Golf i-n+k>~0untuk i-n>~k.
  • Disimpan tiga byte berkat ceilingcat ; b||printf("|"),n++setara dengan 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];}

Cobalah online!


Anda dapat menyimpan 2 byte dengan menghapus tanda kurung dan meletakkan b||printf("%d,",n)di dalam for-loop: 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 byte
Kevin Cruijssen

@KevinCruijssen Terima kasih.
Jonathan Frech

@ceilingcat Terima kasih; kesetaraan rapi, yang satu itu.
Jonathan Frech

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.