Yerel dize dönemleri


20

Yerel süreler

Boş olmayan dize atın s . Yerel süresi ve s indeksinde ı en küçük pozitif tam sayı olduğu , n her biri için bu tür 0 ≤ k <n , elimizdeki s [i + k] = s [i-n + k] her iki tarafın da tanımlandığı zaman. Alternatif olarak, w olmayan bir dizginin minimum uzunluğu, böylece birleştirici ww , s'nin yanına yerleştirilirse , w'nin ikinci kopyası , s indeksi i'de başlarsa , iki dize üst üste geldiklerinde hemfikir olurlar.

Örnek olarak, s = "abaabbab" yerel periyodunu (0 tabanlı) indeks 2'de hesaplayalım .

  • N = 1 : sonra s [2 + 0] ≠ s [2-1 + 0] 'yu deneyin , bu nedenle bu seçim doğru değildir.
  • N = 2'yi deneyin : o zaman s [2 + 0] = s [2-2 + 0] ancak s [2 + 1] ≠ s [2-2 + 1] , bu da doğru değil.
  • N = 3'ü deneyin : o zaman s [2 + 0-3] tanımlanmamıştır, s [2 + 1] = s [2-3 + 1] ve s [2 + 2] = s [2-3 + 2] . Böylece yerel dönem 3'tür.

Burada, ikinci tanımı kullanarak yerel periyotların görselleştirilmesi, w'nin iki kopyası arasına noktalı virgül eklenmesi amacıyla açıklık kazandırılmıştır:

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

Not, ağırlık , zorunlu olarak bir alt değildir s . Bu, burada index-4 durumunda olur.

Görev

Girişiniz boş olmayan bir dize s küçük ASCII karakter. İstenirse bir karakter listesi olarak alınabilir. Çıktınız yerel dönemini içeren liste olacaktır s onun endeksleri her birinde. Yukarıdaki örnekte, doğru çıktı [1,2,3,1,6,1,3,2] olacaktır .

Her dilde en düşük bayt sayısı kazanır. Standart kuralları geçerlidir.

Test senaryoları

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]

Her zaman bulabilirsiniz @Arnauld w ile aynı uzunlukta s . Durumunda qwertyuiop, w döndürülmüş bir versiyonu olacaktır qwertyuiop. Ayrıca indeks 4'teki örneğe bakınız: w mutlaka s'nin bir alt dizesi değildir .
Zgarb

Mantıklı. Meydan okumayı yanlış okudum.
Arnauld

Doğrusal zaman çözümü için hayali bonus! (başka biri gerçek bir ödül sunabilir, bu yüzden denemeye devam et)
user202729

Gerçekten temiz bir meydan okuma, ama her iki pozisyon arasındaki yerel süreyi tanımlamak daha mantıklı olup olmadığını merak ediyorum (yani, örneğin nerede olursa olsun ;). Bu, önde gelen 1'den kurtulur.
Martin Ender

@MartinEnder Bu kavramsal olarak daha temiz olurdu, ancak bu tanım dize üzerinden döngü yaparak çıktının üretilmesini kolaylaştırır ve çıktı boş olmaz.
Zgarb

Yanıtlar:


4

Retina , 89 86 bayt

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

Çevrimiçi deneyin! Düzenleme: @MartinEnder sayesinde 3 bayt kaydedildi. Açıklama:

.
$`¶$<'¶

Biri önek için ve diğeri önek için olmak üzere bir çift satır oluşturarak her karakterdeki girişi bölün.

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

Her bir sonuç çifti için komut dosyasının geri kalanını çalıştırın.

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

Çakışan tüm eşleşmeleri bulun ve sonuçları listeleyin. (Aşağıya bakınız.)

G`.

Boş eşleşmeyi atın.

%C`.

Her maçın uzunluğunu al.

N`

Sayısal olarak sırala.

0G`

En küçüğünü al.

Eşleme, ön ek ve son eki üç parçaya bölerek çalışır. Dikkate alınması gereken dört geçerli durum vardır:

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

Bu nedenle normal ifade, A ve C'nin aynı anda yalnızca bir tarafta eşleşmesine izin verir.


$&$'eşittir $<'ve hesaplama satırı uzunlukları daha kısadır %C`.. tio.run/##K0otycxLNPz/X49LJeHQNhUb9UPbuPQ14mr0tDUPbdPT1o/…
Martin Ender

4

Java 8, 167 154 152 bayt

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 sayesinde -2 bayt .

Çevrimiçi deneyin.

Açıklama:

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 bayt

Girişi bir karakter dizisi olarak alır.

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)

Test senaryoları


Bir dizi karakter almaya izin verilip verilmediğinden emin değilim, sadece 1 karakterli dizeler olmadığından emin misiniz?
Outgolfer Erik

@EriktheOutgolfer JS'de karakter türü yok, bu yüzden evet: teknik olarak 1 karakterli dizelerden oluşan bir dizi. Benim anlayışım bir dize gibi quacks, o bir dize olduğunu. (İşte bununla ilgili bir meta gönderi var, ancak daha alakalı bir tane olabilir - veya aslında varsayımımla çelişen bir tane.)
Arnauld

1
Ya da başka bir deyişle: bu, JS'de OP tarafından açıkça izin verilen bir karakter listesine ulaşabileceğimiz kadar yakın .
Arnauld

1

Yakut , 104102 bayt

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

Çevrimiçi deneyin!

Bir dizeyi kabul eden ve bir dizi döndüren lambda.

-2 bayt: Aralık bitiş noktalarını dizin bağlı koruyucularla değiştir

Ungolfed:

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

@Shaggy sayesinde 1 bayt kaydedildi

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

Çevrimiçi test edin!

açıklama

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

İlk düşüncem, JS yanıtında olduğu gibi, sol alt dize içindeki her karakteri sağ alt dize içindeki karşılık gelen karakterle karşılaştırmaktı. Ancak, Japt'un bir karakteri elde etme yöntemi, dizin negatif veya çok büyükse, dizenin diğer ucuna sararken bu işe yaramaz.

Bunun yerine, çözümüm ikinci alt dizeden bir normal ifade oluşturur ve ilk alt dizede test eder. abaabbabÖrnek olarak test örneğindeki 5. öğeyi ele alalım:

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

Ana hile, ^gerçek bir karakter eşleşene kadar sonsuz şekilde eşleşebilmesidir. Bu, normal ifadenin başlangıcından itibaren herhangi bir sayıda karakteri yok saymamızı sağlarken, diğerlerinin ardışık olarak eşleştirilmesini ve test dizesinin sonunda bitmesini sağlar.

Bunu çok iyi açıkladığımdan emin değilim, bu yüzden lütfen açıklamak istediğiniz bir şey veya açıklanması gereken başka bir şey varsa bize bildirin.



@Shaggy Teşekkürler, o noktalı virgül beni rahatsız
ediyordu

1

C (GCC) , 143 142 140 139 128 126 123 bayt

  • Bir bayt kaydedildi. Golfed !b&&printfiçin b||printf.
  • Kevin Cruijssen sayesinde iki bayt kurtardı . Yerleşimi forhokkabazlayarak döngü gövdesi parantezleri kaldırıldı printf.
  • Bir bayt kaydedildi. Golfed b+=S[i+k]!=S[i-n+k]için b|=S[i+k]-S[i-n+k].
  • On bir bayt kaydedildi. l=strlen(S)Dizenin sonuna ulaştığında kopmak için her iki dizgi işleme döngüsünü koşullandırma gereksinimi ortadan kaldırıldı (boş bir bayt '\0').
  • İki bayt kaydedildi. Golfed i-n+k>~0için i-n>~k.
  • Tavan kedisi sayesinde üç bayt tasarrufu ; b||printf("|"),n++eşittir 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];}

Çevrimiçi deneyin!



@KevinCruijssen Teşekkürler.
Jonathan Frech

@ ceilingcat Teşekkürler; temiz denklik, o.
Jonathan Frech

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.