Локальні періоди струн


20

Місцеві періоди

Візьміть не порожній рядок s . Локальний період з S в індексі я це найменше натуральне число п таке , що для кожного 0 ≤ до <п , ми маємо з [I + K] = s [я-п + K] всякий раз , коли обидві сторони визначено. З іншого боку , це мінімальна довжина непорожній рядки ж таке , що якщо конкатенація WW стоїть поруч з так , що другий примірник ш починається з індексу я в с , то два рядки погоджуються , де вони перекриваються.

Як приклад, давайте обчислимо локальний період s = "abaabbab" за (на основі 0) індексом 2.

  • Спробуйте 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.

Ось візуалізація локальних періодів за допомогою другого визначення, з двома примірниками w для наочності додано крапки з комою :

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.

Завдання

Ваш внесок непорожній рядки s з малих символів 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 Ви завжди можете знайти w з тією ж довжиною, що і s . У випадку qwertyuiop, w буде поворотною версією qwertyuiop. Дивіться також приклад в індексі 4: w не обов'язково є підрядкою s .
Згарб

Що має сенс. Я неправильно прочитав виклик.
Арнольд

Уявний бонус за лінійне рішення часу! (хтось інший може запропонувати справжню винагороду, тому продовжуйте намагатися)
користувач202729

Дійсно акуратний виклик, але мені цікаво, чи було б більше сенсу визначати локальний період кожної позиції між двома символами (тобто де б ;у вашому прикладі не було). Це дозволить позбутися ведучого 1.
Мартін Ендер

@MartinEnder Це було б концептуально чистіше, але це визначення полегшує отримання результату, перебираючи рядок, і вихід не буде порожнім.
Згарб

Відповіді:


4

Сітківка , 89 86 байт

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

Спробуйте в Інтернеті! Редагувати: збережено 3 байти завдяки @MartinEnder. Пояснення:

.
$`¶$<'¶

Розділіть вхід на кожен символ, створивши пару рядків, один для префікса і один для суфікса префікса.

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

Запустіть решту сценарію на кожній отриманій парі.

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

Знайдіть усі збіги, що збігаються, і перерахуйте результати. (Дивіться нижче.)

G`.

Відмовтеся від порожнього збігу.

%C`.

Візьміть довжину кожного матчу.

N`

Сортувати чисельно.

0G`

Візьміть найменший.

Збіг працює, розбиваючи префікс і суфікс на три частини. Слід розглянути чотири дійсні випадки:

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

-2 байти завдяки @ceilingcat .

Спробуйте в Інтернеті.

Пояснення:

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-символьних рядків. Я розумію, що якщо вона б'ється як рядок, це струна. (Ось мета-повідомлення про це, але може існувати більш релевантний - або той, що насправді суперечить моєму припущенню.)
Арнольд

1
Або кажучи іншими словами: це настільки близько, наскільки ми можемо потрапити до списку символів JS, який явно дозволив ОП.
Арнольд

1

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

Japt , 33 32 байт

Збережено 1 байт завдяки @Shaggy

¬Ë@¯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. Однак це не буде працювати, оскільки метод Джапта, щоб отримати символ просто загортається на інший кінець рядка, якщо індекс негативний або занадто великий.

Натомість моє рішення будує регулярний вираз із другої підрядки і тестує його на першій підрядковій лінії. Візьмемо abaabbabдля прикладу 5-й предмет у тестовому випадку :

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

Основна хитрість полягає в тому, що ^може відповідати нескінченно, до тих пір, поки фактичний персонаж не зрівняється. Це дозволяє нам ігнорувати будь-яку кількість символів з початку регексу, гарантуючи, що всі решти послідовно узгоджуються, закінчуючи в кінці тестового рядка.

Я не впевнений, що я це дуже добре пояснив, тому, будь ласка, дайте мені знати, чи є щось, що ви хотіли б уточнити, або щось інше, що слід пояснити.



@Shaggy Спасибі, що точка з комою переймала мене: P
ETHproductions,

1

C (gcc) , 143 142 140 139 128 126 123 байт

  • Збережено байт. Гольф !b&&printfдо b||printf.
  • Збережено два байти завдяки Kevin Cruijssen . Видалено forкруглі дужки корпусу циклу, ввімкнувши printfрозміщення.
  • Збережено байт. Гольф b+=S[i+k]!=S[i-n+k]до b|=S[i+k]-S[i-n+k].
  • Збережено одинадцять байтів. Вилучено необхідність l=strlen(S), обумовивши обидва циклу обробки рядків для розриву при досягненні кінця рядка (нульовий байт '\0').
  • Збережено два байти. Гольф i-n+k>~0до i-n>~k.
  • Збережено три байти завдяки плафоні ; 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)всередину 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]);}
фор

@KevinCruijssen Дякую
Джонатан Фрех

@ceilingcat Спасибі; акуратний еквівалент, той.
Джонатан Фрех

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.