Ідеальні Паліндроми


25

Ваше завдання - визначити, наскільки досконала паліндромна струна. Ваш типовий паліндром (наприклад, 12321) - ідеальний паліндром; її досконалість - 1.

Щоб визначити досконалість рядка, ви бачите, на скільки розділів ви можете розділити його там, де кожен розділ є паліндром. Якщо є двозначності, наприклад, з aaaa, як ви можете розділити його на [aa, aa]або, [aaaa]або, [a, aaa]або [aaa, a]найкоротший набір буде перевершено, даючи aaaaбал 1, що є довжиною найкоротшого набору.

Тому ви повинні написати програму або функцію, яка буде приймати один не порожній вхід і виводити наскільки він ідеальний (яка довжина найкоротшого набору ви можете розділити на ту, де кожен елемент у наборі є паліндром).

Приклади:

1111 -> 1 [1111]
abcb -> 2 [a, bcb]
abcbd -> 3 [a, bcb, d]
abcde -> 5 [a, b, c, d, e]
66a -> 2 [66, a]
abcba-> 1 [abcba]
x -> 1 [x]
ababacab -> 2 [aba, bacab]
bacababa -> 2 [bacab, aba]
26600 -> 3 [2, 66, 00] [my user id] [who has a more perfect user id?]
ababacabBACABABA -> 4 [aba, bacab, BACAB, ABA]

Зауважте, що у прикладах нічого, що є у квадратних дужках, не повинно бути частиною результату.


Чи пустий рядок є коректним вводом, і якщо так, яким повинен бути вихід?
Згарб

8
ababacabі його зворотний бік, bacababaздається, хороші тестові випадки.
Ніл

@Neil, а також хороші аргументи щодо того, чи можливий алгоритм лінійного часу.
Leaky Nun

@Zgarb Порожній рядок недійсний.
Okx

ababacabBACABABAце також хороший тестовий випадок (деякі відповіді на нього не вдається).
Згарб

Відповіді:


14

Брахілог , 7 байт

~cL↔ᵐLl

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

Пояснення

~cL          Deconcatenate the input into L
  L↔ᵐL       Reversing all elements of L results in L
     Ll      Output = length(L)

Ти побив мене ... на моєму першому дописі, хай
Лина монашка

7
@LeakyNun Я знав, що ти спробуєш. Останні місяці я міг збитися і почекати кілька годин, тепер з вами назад я маю відповісти негайно!
Фаталізувати

9

Желе , 13 12 11 байт

ŒṖLÞŒḂ € P $ ÐfḢL 
ŒṖLÞṚ € ⁼ $ ÐfḢL
ŒṖṚ € ⁼ $ ÐfL € Ṃ
ŒṖ отримати розділи
      Ðf фільтр для розділів, які
  Ṛ € після скасування кожного підрозділу
    ⁼ дорівнює перегородці
        L € довжина кожного успішного розділу
          Ṃ мінімум

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

Технічні характеристики

  • Введення: "ababacab"(як аргумент)
  • Вихід: 2

3
@Oxx добре, вам доведеться уникнути цих.
Leaky Nun

2
Ну, я не думаю, що це справедливо, якщо він не може приймати зворотні нахили.
Okx

14
@Okx Це як написання рядка. Ви не можете очікувати, скажімо, програми C для роботи зі введенням рядка "\", оскільки це недійсний синтаксис.
Conor O'Brien

2
Ласкаво просимо назад, до речі. :-)
Арнольд

2
До жаль , це дає різні відповіді ababacabі його зворотне, bacababa.
Ніл

6

Pyth, 9 байт

lh_I#I#./

Тестовий набір

Це формує всі розділи вводу, від найкоротших до найдовших. Потім він фільтрує ті розділи на інваріантність під фільтруванням елементів на інваріантності під час обертання. Нарешті, ми беремо перший елемент відфільтрованого списку розділів і повертаємо його довжину.

Для того, щоб пояснити , що складний крок, давайте почнемо з інваріантності щодо звернення: _I. Це перевіряє, чи є його вхід паліндром, оскільки він перевіряє, чи змінюється зворотне значення значення.

Далі, для фільтрації паліндромності: _I#. Це збереже лише паліндромні елементи списку.

Далі ми перевіряємо на інваріантність щодо фільтрації для паліндромності: _I#I. Це правда, якщо і лише тоді, коли всі елементи списку є паліндрами.

Нарешті, ми фільтруємо для списків , де всі елементи списку є палиндромов: _I#I#.


У мене є чому навчитися ...
Leaky Nun

6

Haskell , 83 байти

f s=minimum[length x|x<-words.concat<$>mapM(\c->[[c],c:" "])s,all((==)=<<reverse)x]

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

Це використовує чудову пораду Згарба для створення рядкових розділів .

f s = minimum[                               -- take the minimum of the list
    length x |                               -- of the number of partitions in x
    x<-words.concat<$>mapM(\c->[[c],c:" "])s -- where x are all partitions of the input string s
    , all((==)=<<reverse)x                   -- where each partition is a palindrome.
]

1
Оце Так! Це підірвало мій розум! Я, безумовно, маю багато чому навчитися.
maple_shaft

5

Clojure, 111 байт

(defn f[s](if(=()s)0(+(apply min(for[i(range(count s))[a b][(split-at(inc i)s)]:when(=(reverse a)a)](f b)))1)))

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

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

Ungolfed, використовує макрос-останній потік ->> .

(defn f [s]
  (if (empty? s)
    0
    (let [results (for[i (range(count s))]
                      (let [[a b] (split-at (inc i) s)]
                         (when (= a (reverse a))
                           (f b))))]
      (->> results        ; Take results (a list of integers and nils),
           (filter some?) ; remove null values (they occur when "a" is not a palindrome)
           (apply min)    ; find the minium value,
           inc))))        ; and increment by one.

Незрозуміла версія, будь ласка, не пишіть такий код: D

(defn f [s]
   (->> (f b)
        (when (= a (reverse a)))
        (let [[a b] (split-at (inc i) s)])
        (for[i (range(count s))])
        (filter some?)
        (apply min)
        inc
        (if (empty? s) 0)))

Чи допомогла б ця порада ? Я взагалі не знаю Clojure.
Leaky Nun

Зазвичай так, але в цьому випадку функція fповинна називати себе всередині для: (f b). У позиції виклику хвоста ви можете використовувати recur.
NikoNyrh

Ви все ще можете замінити defnз fnі просто мати функцію.
Скеля

(fn f[s]( ... ))? О правда. З цим ви зберігаєте 2 символи.
NikoNyrh

5

JavaScript (ES6), 143 126 124 байт

Збережено 2 байти завдяки Нілу

Натхненний методом NikoNyrh .

s=>(r=1/0,F=(s,i=1,p=0)=>s[p++]?([...o=s.slice(0,p)].reverse().join``==o&&(s[p]?F(s.slice(p),i+1):r=r<i?r:i),F(s,i,p)):r)(s)

Відформатовано та прокоментовано

s => (                          // given a string 's':
  r = 1 / 0,                    // 'r' = best score, initialized to +Infinity
  F = (                         // 'F' is a recursive function that takes:
    s,                          //   - the current string 's'
    i = 1,                      //   - a substring counter 'i'
    p = 0                       //   - a character pointer 'p'
  ) =>                          //
    s[p++] ? (                  // if we haven't reached the end of the string:
      [...o = s.slice(0, p)]    //   compute 'o' = substring of length 'p'
      .reverse().join`` == o    //   if 'o' is a palindrome,
      && (                      //   then:
        s[p] ?                  //     if there are still characters to process:
          F(s.slice(p), i + 1)  //       do a recursive call on the remaining part
        :                       //     else:
          r = r < i ? r : i     //       update the score with r = min(r, i)
      ),                        //   in all cases:
      F(s, i, p)                //     do a recursive call with a longer substring
    ) :                         // else:
      r                         //   return the final score
  )(s)                          // initial call to F()

Тестові справи


Початковий підхід, 173 168 байт

Досить довга рекурсивна функція, яка обчислює всі можливі розділи вхідного рядка.

f=(s,b=1/(k=0))=>++k>>(L=s.length)?b:f(s,(k|1<<30).toString(2).slice(-L).match(/(.)\1*/g).some(m=>[...o=s.slice(i,i+=m.length)].reverse(n++).join``!=o,n=i=0)?b:b<n?b:n)

Відформатовано та прокоментовано

f = (                           // given:
  s,                            //   - a string 's'
  b = 1 / (k = 0)               //   - a best score 'b' (initialized to +Infinity)
) =>                            //   - a counter 'k' (initialized to 0)
  ++k >> (L = s.length) ?       // if 'k' is greater or equal to 2^(s.length):
    b                           //   stop recursion and return 'b'
  :                             // else:
    f(                          //   do a recursive call:
      s,                        //     using the same string 's'
      (k | 1 << 30)             //     compute an array containing the groups of identical
      .toString(2).slice(-L)    //     digits in the binary representation of 'k', padded
      .match(/(.)\1*/g)         //     with leading zeros and cut to the length of 's'
      .some(g =>                //     for each group 'g' in this array:
        [... o = s.slice(       //       compute 'o' = corresponding substring of 's',
          i, i += g.length      //       starting at position 'i' with the same length
        )]                      //       (e.g. s = 'abcd' / k = 0b1101 => 'ab','c','d')
        .reverse(n++)           //       increment the number of groups 'n'
        .join`` != o,           //       return true if this substring is NOT a palindrome
        n = i = 0               //       initialize 'n' and 'i'
      ) ?                       //     if some() returns true:
        b                       //       invalid partition -> keep the previous score 'b'
      :                         //     else:
        b < n ? b : n           //       valid partition -> use min(b, n)
    )                           //   end of recursive call

Тестові справи


Якщо я правильно зрозумів ваше пояснення, ви можете заощадити пару байтів , використовуючи ,p=0, s[p++]?і ,F(s,i,p).
Ніл

@Neil Так. :-)
Арнольд

5

Желе , 10 байт

ŒṖŒḂ€¬$ÞḢL

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

Як?

Використовується той факт, що
[0]<[0,0]<[0,0,0],...,<[0,...,0,1]<...
- таким чином, якщо ми сортуємо розділи за клавішею "не паліндромно для кожної частини", перший запис буде паліндромним та мінімальної довжини.

Примітка: будь-який не порожній рядок довжиною n завжди призведе до такого ключа з n нулями, оскільки всі рядки довжиною 1 є паліндромними.

ŒṖŒḂ€¬$ÞḢL - Main link: s             e.g. 'abab'
ŒṖ         - partitions of s               [['a','b','a','b'],['a','b','ab'],['a','ba','b'],['a','bab'],['ab','a','b'],['ab','ab'],['aba','b'],['abab']]
       Þ   - sort by (create the following key and sort the partitions by it):
      $    -   last two links as a monad:  (key evaluations aligned with above:)
  ŒḂ€      -     is palindromic? for €ach   [ 1 , 1 , 1 , 1 ] [ 1 , 1 , 0  ] [ 1 , 0  , 1 ] [ 1 , 1   ] [ 0  , 1 , 1 ] [ 0  , 0  ] [ 1   , 1 ] [ 0    ] 
     ¬     -     not                        [ 0 , 0 , 0 , 0 ] [ 0 , 0 , 1  ] [ 0 , 1  , 0 ] [ 0 , 0   ] [ 1  , 0 , 0 ] [ 1  , 1  ] [ 0   , 0 ] [ 1    ]
           - ...i.e.:         
           -       making the sorted keys: [[ 0 , 0   ],[ 0   , 0 ],[ 0 , 0 , 0 , 0 ],[ 0 , 0 , 1  ],[ 0 , 1  , 0 ],[ 1    ],[ 1  , 0 , 0 ],[ 1  , 1  ]]
           -  hence the sorted partitions: [['a','bab'],['aba','b'],['a','b','a','b'],['a','b','ab'],['a','ba','b'],['abab'],['ab','a','b'],['ab','ab']]
        Ḣ  - head of the result             ['a','bab']
         L - length                         2

5

Haskell , 69 байт

x!(a:b)|p<-a:x=p!b++[1+f b|p==reverse p]
x!y=[0|x==y]
f=minimum.(""!)

Визначає функцію f. Спробуйте в Інтернеті!

Пояснення

Функція помічника інфікування x ! yобчислює список цілих чисел, які є довжинами деяких розщеплень reverse x ++ yна паліндроми, де reverse xзалишено недоторканим. Гарантовано містити довжину мінімального розщеплення, якщо yвоно не порожнє. Як це працює, це так.

  • Якщо він yне порожній, з нього вискакує картка і всувається x. Якщо xстає паліндром, ми називаємо основну функцію fна хвості yі додаємо 1 для обліку x. Також ми закликаємо !нове xі yне пропускати жодного потенційного розколу.
  • Якщо yпорожній, ми повертаємося [0](один розщеплення довжини 0), якщо xвін також порожній, а [](без розщеплення) інакше.

Основна функція fпросто викликає "" ! xі приймає мінімум результатів.

x!(a:b)|          -- Function ! on inputs x and list with head a and tail b,
  p<-a:x=         -- where p is the list a:x, is
  p!b++           -- the numbers in p!b, and
  [1+f b|         -- 1 + f b,
   p==reverse p]  -- but only if p is a palindrome.
x!y=              -- Function ! on inputs x and (empty) list y is
  [0|             -- 0,
   x==y]          -- but only if x is also empty.
f=                -- Function f is:
  minimum.(""!)   -- evaluate ! on empty string and input, then take minimum.

3

JavaScript (Firefox 30-57), 97 байт

f=(s,t=``,i=0)=>s?Math.min(...(for(c of s)if([...t+=c].reverse(++i).join``==t)1+f(s.slice(i)))):0

Порт ES6:

f=(s,t=``)=>s?Math.min(...[...s].map((c,i)=>[...t+=c].reverse().join``==t?1+f(s.slice(i+1)):1/0)):0
<input oninput=o.textContent=f(this.value)><pre id=o>

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


1

Haskell, 139 116 109 байт

h[]=[[]]
h x=words.concat<$>mapM(\c->[[c],c:" "])x
r x=reverse x==x
g x=minimum[length y|y<-h x,and$r<$>y]

Все ще зелений в гольф Haskell, але ось моя найкраща спроба, яку я можу швидко придумати.

  • h - це функція, яка створює Список усіх можливих суміжних підрядів Списку (як рядок). Він бере вхідну рядок і розбиває її на g.
  • r - проста функція, яка повертає булеву форму, якщо список є паліндром
  • g - основна функція, яка приймає список введення, викликає h, щоб отримати список суміжних можливостей (and.map r)підпорядкування , фільтрує для видалення підсписів, які не містять паліндром, при якій довжина точки застосовується до списку, і тоді результат є відсортовано, щоб ми могли схопити голову, що є відповіддю.

Я думав, що кращою відповіддю може вдатися використання недетермінованого характеру списків у Haskell шляхом використання додатків. Можливо, можливо, відшарувати багато байтів від функції h за допомогою додатків, навіть якщо нам доведеться імпортувати Control.Applicative. Коментарі до вдосконалення вітаються.

ОНОВЛЕННЯ1

Величезні заощадження, засновані на нагадуванні Лайконі про мінімальну функцію. Видалення сорту фактично дозволило мені скинути імпорт Data.List, оскільки мінімум визначено в Prelude!

ОНОВЛЕННЯ2

Завдяки пропозиції німі про використання розуміння списку як корисної заміни filter.map. Це врятувало мені кілька байт. Також я запозичив акуратний трюковий розділ з відповіді Лайконіса і там також врятував пару байтів.


1
h []=[[]]і h (x:y)=map ([x]:)містять зайвий пробіл. head.sortє minimum.
Лайконі

@Laikoni Дякую! Я оновлюсь, коли повернусь до свого комп’ютера!
maple_shaft

1
Список розуміння часто коротше filterі map: g x=head$sort[length y|y<-h x,and$r<$>y].
німі

@nimi Дякую, для Haskell так багато корисних порад для гольфу. Я щоразу дізнаюся нову хитрість.
maple_shaft

1

PHP, 319 байт

for(;$i<$l=strlen($s=$argn);$i++)for($j=$l-$i;$j;$j--)strrev($r=substr($s,$i,$j))!=$r?:$e[+$i][]=$r;uasort($e,function($a,$b){return strlen($b[0])<=>strlen($a[0])?:count($a)<=>count($b);});foreach($e as$p=>$v)foreach($v as$w){$s=preg_replace("#^(.{{$p}})$w#","$1".str_pad("",strlen($w),"ö"),$s,1,$c);!$c?:++$d;}echo$d;

Інтернет-версія

Розширено

for(;$i<$l=strlen($s=$argn);$i++)
for($j=$l-$i;$j;$j--)strrev($r=substr($s,$i,$j))!=$r?:$e[+$i][]=$r; #Make all substrings that are palindromes for each position
uasort($e,function($a,$b){return strlen($b[0])<=>strlen($a[0])?:count($a)<=>count($b);}); # sort palindrome list high strlen lowest count for each position
foreach($e as$p=>$v)
foreach($v as$w){
    $s=preg_replace("#^(.{{$p}})$w#","$1".str_pad("",strlen($w),"ö"),$s,1,$c);
    !$c?:++$d; # raise count
}
echo$d; # Output

Більш довга версія без E_NOTICE та виведіть отриманий масив


Це, здається, дає неправильний результат дляababacabBACABABA
Zgarb

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