Palindromes parfaits

25

Votre tâche consiste à déterminer la quantité d'un palindrome parfait d'une chaîne. Votre palindrome typique (par exemple 12321) est un palindrome parfait; sa perfection est de 1.

Pour déterminer la perfection d'une chaîne, vous voyez combien de sections vous pouvez la diviser en où chaque section est un palindrome. S'il y a des ambiguïtés, comme avec aaaa, comme vous pouvez le diviser en [aa, aa]ou [aaaa]ou [a, aaa]ou [aaa, a], l'ensemble le plus court prévaudra, donnant aaaaun score de 1, qui est la longueur de l'ensemble le plus court.

Par conséquent, vous devez écrire un programme ou une fonction qui prendra une entrée non vide et affichera sa perfection (qui est la longueur de l'ensemble le plus court, vous pouvez le diviser en où chaque élément de l'ensemble est un palindrome).

Exemples:

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]

Notez que dans les exemples, tout ce qui est entre crochets ne doit pas faire partie de la sortie.

Okx
la source
La chaîne vide est-elle une entrée valide, et si oui, quelle devrait être la sortie?
Zgarb
8
ababacabet son inverse, bacababasemblent être de bons cas de test.
Neil
@Neil ainsi que de bons arguments pour savoir si un algorithme à temps linéaire est possible.
Leaky Nun
@Zgarb Une chaîne vide n'est pas une entrée valide.
2017
ababacabBACABABAest également un bon cas de test (certaines réponses échouent).
Zgarb

Réponses:

14

Brachylog , 7 octets

~cL↔ᵐLl

Essayez-le en ligne!

Explication

~cL          Deconcatenate the input into L
  L↔ᵐL       Reversing all elements of L results in L
     Ll      Output = length(L)
Fatalize
la source
Tu m'as battu ... sur mon premier post lol
Leaky Nun
7
@LeakyNun Je savais que vous l'essayeriez. Les derniers mois, j'ai pu me relâcher et attendre quelques heures, maintenant avec vous, je dois répondre immédiatement!
Fatalize
9

Gelée , 13 12 11 octets

ŒṖLÞŒḂ € P $ ÐfḢL 
ŒṖLÞṚ € ⁼ $ ÐfḢL
ŒṖṚ € ⁼ $ ÐfL € Ṃ
ŒṖ obtenir des partitions
      Ðf filtre pour les partitions qui
  Ṛ € après inversion de chaque sous-partition
    ⁼ est égal à la partition
        L € longueur de chaque partition réussie
          Ṃ minimum

Essayez-le en ligne!

Spécifications

  • Entrée: "ababacab"(comme argument)
  • Sortie: 2
Leaky Nun
la source
3
@Okx et bien tu devrais y échapper.
Leaky Nun
2
Eh bien, je ne pense pas que ce soit valide s'il ne peut pas accepter de barres obliques inverses.
2017
14
@Okx C'est comme écrire une chaîne. Vous ne pouvez pas vous attendre, par exemple, à ce qu'un programme C fonctionne avec une entrée de chaîne "\", car cette syntaxe n'est pas valide.
Conor O'Brien
2
Bon retour, au fait. :-)
Arnauld
2
Malheureusement , cela donne des réponses différentes pour ababacabet son inverse, bacababa.
Neil
6

Pyth, 9 octets

lh_I#I#./

Suite de tests

Cela forme toutes les partitions de l'entrée, de la plus courte à la plus longue. Ensuite, il filtre ces partitions sur l'invariance en filtrant les éléments sur l'invariance en inversion. Enfin, nous prenons le premier élément de la liste filtrée des partitions et retournons sa longueur.

Pour expliquer cette étape compliquée, nous allons commencer par invariance par inversion: _I. Cela vérifie si son entrée est un palindrome, car il vérifie si l'inversion change la valeur.

Ensuite, le filtrage pour palindromicity: _I#. Cela ne conservera que les éléments palindromiques de la liste.

Ensuite, nous vérifions invariance sous filtrage pour palindromicity: _I#I. C'est vrai si et seulement si tous les éléments de la liste sont des palindromes.

Enfin, on filtre pour les listes où tous les éléments de la liste sont palindromes: _I#I#.

isaacg
la source
J'ai beaucoup à apprendre ...
Leaky Nun
6

Haskell , 83 octets

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

Essayez-le en ligne!

Cela utilise la grande astuce de Zgarb pour générer des partitions de chaînes .

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.
]
Laikoni
la source
1
Hou la la! Cela m'a époustouflé! J'ai certainement beaucoup à apprendre.
maple_shaft
5

Clojure, 111 octets

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

Se divise à toutes les positions possibles, et lorsque la première partie est un palindrome, procède à la recherche d'un partitionnement pour le reste de la chaîne.

Essayez-le en ligne .

Non golfé, utilise une macro de filetage ->> .

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

Une version obscure, veuillez ne pas écrire de code comme ceci: 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)))
NikoNyrh
la source
Cette astuce serait -elle utile? Je ne connais pas du tout Clojure.
Leaky Nun
En général , oui, mais dans ce cas , la fonction fdoit s'appeler dans le pour: (f b). Sur une position de queue d'appel, vous pouvez utiliser recur.
NikoNyrh
Vous pouvez toujours remplacer defnpar fnet juste avoir une fonction.
cliffroot
(fn f[s]( ... ))? Oh c'est vrai. Vous enregistrez 2 caractères avec cela.
NikoNyrh
5

JavaScript (ES6), 143 126 124 octets

Enregistré 2 octets grâce à Neil

Inspiré de la méthode 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)

Formaté et commenté

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

Cas de test


Approche initiale, 173 168 octets

Une fonction récursive assez longue qui calcule toutes les partitions possibles de la chaîne d'entrée.

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)

Formaté et commenté

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

Cas de test

Arnauld
la source
Si je comprends bien votre explication, vous pouvez enregistrer deux octets en utilisant ,p=0, s[p++]?et ,F(s,i,p).
Neil
@Neil Oui en effet. :-)
Arnauld
5

Gelée , 10 octets

ŒṖŒḂ€¬$ÞḢL

Essayez-le en ligne!

Comment?

Utilise le fait que
[0]<[0,0]<[0,0,0],...,<[0,...,0,1]<...
- donc si nous trions les partitions par une clé "n'est pas palindromique pour chaque partie" la première entrée sera tout palindromique et de longueur minimale.

Remarque: toute chaîne non vide de longueur n entraînera toujours une telle clé avec n zéros, car toutes les chaînes de longueur 1 sont palindromiques.

ŒṖŒḂ€¬$ÞḢ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
Jonathan Allan
la source
5

Haskell , 69 octets

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

Définit une fonction f. Essayez-le en ligne!

Explication

La fonction d'aide infixe x ! ycalcule une liste d'entiers, qui sont les longueurs de certaines divisions de reverse x ++ ypalindromes où reverse xest laissé intact. Il est garanti de contenir la longueur du fractionnement minimal s'il yn'est pas vide. Voici comment cela fonctionne.

  • S'il yn'est pas vide, un caractère est sauté et poussé dedans x. Si xdevient un palindrome, nous appelons la fonction principale fsur la queue de yet ajoutons 1 pour tenir compte x. Aussi, nous appelons !le nouveau xet yà ne rater aucun éventuel fractionnement.
  • Si yest vide, nous retournons [0](un fractionnement de longueur 0) si xest également vide, et [](pas de fractionnement) sinon.

La fonction principale fappelle simplement "" ! xet prend le minimum de résultats.

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.
Zgarb
la source
3

JavaScript (Firefox 30-57), 97 octets

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

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

Cela semble une solution si simple que je continue de penser que j'ai oublié quelque chose, mais elle réussit au moins tous les cas de test.

Neil
la source
1

Haskell, 139 116 109 octets

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]

Toujours vert au golf de Haskell, mais voici ma meilleure tentative que je peux trouver rapidement.

  • h est une fonction qui crée une liste de toutes les sous-séquences contiguës possibles d'une liste (comme une chaîne). Il prend la chaîne d'entrée et la décompose pour g.
  • r est une fonction simple qui renvoie un booléen si une liste est un palindrome
  • g est la fonction principale qui prend une liste d'entrée, appelle h pour obtenir la liste des possibilités de sous-séquences contiguës, filtre (and.map r)pour supprimer les sous-listes qui ne contiennent pas de palindrome, à quelle longueur de point est appliquée à la liste, puis le résultat est triés afin que nous puissions saisir la tête qui est la réponse.

Je pensais qu'une meilleure réponse pourrait être en mesure de tirer parti de la nature non déterministe des listes de Haskell grâce à l'utilisation de candidats. Il peut être possible de raser plusieurs octets de la fonction h en utilisant des applicatifs, même si nous devons importer Control.Applicative. Les commentaires d'amélioration sont les bienvenus.

UPDATE1

D'énormes économies basées sur le rappel de Laikoni sur la fonction minimale. La suppression du tri m'a en fait permis de supprimer l'importation Data.List car le minimum est défini dans Prelude!

UPDATE2

Merci à la suggestion de nimi d'utiliser des listes de compréhension comme remplacement utile pour filter.map. Cela m'a fait économiser quelques octets. J'ai également emprunté l'astuce de partition de chaîne soignée à la réponse de Laikonis et y ai également enregistré quelques octets.

maple_shaft
la source
1
h []=[[]]et h (x:y)=map ([x]:)contiennent des espaces blancs inutiles. head.sortest minimum.
Laikoni
@Laikoni Merci! Je mettrai à jour quand je reviendrai à mon ordinateur!
maple_shaft
1
Une compréhension de la liste est souvent plus courte que filter& map: g x=head$sort[length y|y<-h x,and$r<$>y].
nimi
@nimi Merci, il y a tellement de conseils de golf utiles pour Haskell. J'apprends un nouveau tour à chaque fois.
maple_shaft
1

PHP, 319 octets

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;

Version en ligne

Étendu

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

Version plus longue sans E_NOTICE et sortie du tableau résultant

Jörg Hülsermann
la source
Cela semble donner un résultat incorrect pourababacabBACABABA
Zgarb
@Zgarb Maintenant ça marche
Jörg Hülsermann