Palindromi perfetti


25

Il tuo compito è determinare quanta parte di un palindromo perfetto è una stringa. Il tuo tipico palindromo (ad es. 12321) è un palindromo perfetto; la sua perfezione è 1.

Per determinare la perfezione di una stringa, vedi quante sezioni puoi dividerla in cui ogni sezione è un palindromo. Se ci sono ambiguità, come con aaaa, come puoi dividerlo in [aa, aa]o [aaaa]o [a, aaa]o [aaa, a], il set più corto avrà la precedenza, dando aaaaun punteggio di 1, che è la lunghezza del set più breve.

Pertanto, è necessario scrivere un programma o una funzione che prenda un input non vuoto e produca quanto è perfetto (qual è la lunghezza dell'insieme più corto in cui è possibile dividerlo in cui ogni elemento dell'insieme è un palindromo).

Esempi:

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]

Si noti che negli esempi qualsiasi cosa tra parentesi quadre non dovrebbe far parte dell'output.


La stringa vuota è un input valido e, in tal caso, quale dovrebbe essere l'output?
Zgarb,

8
ababacabe il suo rovescio, bacababasembrano essere buoni casi di test.
Neil,

@Neil, oltre a validi argomenti sulla possibilità di un algoritmo a tempo lineare.
Leaky Nun,

@Zgarb La stringa vuota non è un input valido.
Okx,

ababacabBACABABAè anche un buon caso di test (alcune risposte falliscono).
Zgarb,

Risposte:


14

Brachylog , 7 byte

~cL↔ᵐLl

Provalo online!

Spiegazione

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

Mi hai battuto ... sul mio primo post lol
Leaky Nun

7
@LeakyNun Sapevo che l'avresti provato. Negli ultimi mesi ho potuto rilassarmi e aspettare qualche ora, ora con te devo rispondere immediatamente!
Fatalizza il

9

Gelatina , 13 12 11 byte

ŒṖLÞŒḂ € P $ ÐfḢL 
ŒṖLÞṚ € ⁼ $ ÐfḢL
ŒṖṚ € ⁼ $ DFL € M
ŒṖ ottenere partizioni
      Ðf filtro per partizioni che
  Ṛ € dopo aver invertito ogni sottopartizione
    ⁼ è uguale alla partizione
        L € lunghezza di ogni partizione riuscita
          Ṃ minimo

Provalo online!

Specifiche

  • Input: "ababacab"(come argomento)
  • Produzione: 2

3
@Okx bene dovresti scappare da quelli.
Leaky Nun,

2
Bene, non penso che sia valido se non può accettare barre rovesciate.
Okx,

14
@Okx È come scrivere una stringa. Ad esempio, non puoi aspettarti che un programma C funzioni con un input di stringa "\", perché questa è una sintassi non valida.
Conor O'Brien,

2
Bentornato, comunque. :-)
Arnauld

2
Purtroppo questo dà risposte diverse per ababacabe il suo rovescio, bacababa.
Neil,

6

Pyth, 9 byte

lh_I#I#./

Suite di test

Ciò costituisce tutte le partizioni dell'input, dal più breve al più lungo. Quindi, filtra quelle partizioni sull'invarianza sotto il filtro degli elementi sull'invarianza al contrario. Infine, prendiamo il primo elemento dell'elenco filtrato delle partizioni e ne restituiamo la lunghezza.

Per spiegare questo passo complicato, cominciamo con invarianza sotto inversione: _I. Ciò controlla se il suo input è un palindromo, perché controlla se l'inversione modifica il valore.

Successivamente, il filtro per palindromicity: _I#. Ciò manterrà solo gli elementi palindromici dell'elenco.

Successivamente, abbiamo verificare la presenza di invarianza sotto il filtraggio per palindromicity: _I#I. Questo è vero se e solo se tutti gli elementi dell'elenco sono palindromi.

Infine, filtriamo per le liste in cui tutti gli elementi della lista sono palindromi: _I#I#.


Ho molto da imparare ...
Leaky Nun,

6

Haskell , 83 byte

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

Provalo online!

Questo usa l'ottimo consiglio di Zgarb per generare partizioni di stringa .

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
Wow! Questo mi ha fatto impazzire! Ho sicuramente molto da imparare.
maple_shaft

5

Clojure, 111 byte

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

Si divide in tutte le posizioni possibili e quando la prima parte è un palindromo procede alla ricerca di un partizionamento per il resto della stringa.

Provalo online .

Ungolfed, usa la macro thread-last ->> .

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

Una versione oscura, per favore non scrivere codice come questo: 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)))

Questo suggerimento sarebbe d' aiuto? Non conosco affatto Clojure.
Leaky Nun,

Di solito sì, ma in questo caso la funzione fdeve chiamare se stesso all'interno della di: (f b). È possibile utilizzare una posizione di coda chiamata recur.
NikoNyrh,

Puoi ancora sostituire defncon fne avere solo una funzione.
cliffroot,

(fn f[s]( ... ))? Oh vero Salva 2 personaggi con quello.
NikoNyrh,

5

JavaScript (ES6), 143 126 124 byte

Salvato 2 byte grazie a Neil

Ispirato al metodo 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)

Formattato e commentato

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

Casi test


Approccio iniziale, 173 168 byte

Una funzione ricorsiva piuttosto lunga che calcola tutte le possibili partizioni della stringa di input.

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)

Formattato e commentato

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

Casi test


Se ho capito bene la tua spiegazione, puoi salvare un paio di byte usando ,p=0, s[p++]?e ,F(s,i,p).
Neil,

@Neil Sì davvero. :-)
Arnauld

5

Gelatina , 10 byte

ŒṖŒḂ€¬$ÞḢL

Provalo online!

Come?

Usa il fatto che
[0]<[0,0]<[0,0,0],...,<[0,...,0,1]<...
, quindi se ordiniamo le partizioni per chiave "non è palindromico per ogni parte" la prima voce sarà tutta palindromica e di lunghezza minima.

Nota: qualsiasi stringa non vuota di lunghezza n determinerà sempre tale chiave con n zero, poiché tutte le stringhe di lunghezza 1 sono palindromiche.

ŒṖŒḂ€¬$ÞḢ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 byte

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

Definisce una funzione f. Provalo online!

Spiegazione

La funzione helper infix x ! ycalcola un elenco di numeri interi, che sono le lunghezze di alcune suddivisioni reverse x ++ yin palindromi dove reverse xviene lasciato intatto. È garantito contenere la lunghezza della divisione minima se ynon vuota. Come funziona è questo.

  • Se yè vuoto, un carattere viene saltato fuori da esso e spinto dentro x. Se xdiventa un palindromo, chiamiamo la funzione principale fsulla coda di ye aggiungiamo 1 per tenere conto x. Inoltre, noi chiamiamo !il nuovo xe yper non perdere alcun potenziale scissione.
  • Se yè vuoto, restituiamo [0](una divisione della lunghezza 0) se xè anche vuoto e [](nessuna divisione) altrimenti.

La funzione principale fchiama "" ! xe prende il minimo dei risultati.

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 byte

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

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

Sembra una soluzione così semplice che continuo a pensare di aver dimenticato qualcosa, ma almeno supera tutti i casi di test.


1

Haskell, 139 116 109 byte

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]

Ancora verde al golf di Haskell, ma qui è il mio miglior tentativo che posso trovare rapidamente.

  • h è una funzione che crea un Elenco di tutte le possibili sottosequenze contigue di un Elenco (come una stringa). Prende l'input String e lo suddivide per g.
  • r è una semplice funzione che restituisce un valore booleano se una lista è un palindromo
  • g è la funzione principale che accetta un elenco di input, chiama h per ottenere l'elenco di possibilità (and.map r)di sottosequenza contigue, filtra per rimuovere gli elenchi secondari che non contengono un palindromo, a quel punto la lunghezza del punto viene applicata all'elenco e quindi il risultato è ordinati in modo da poter afferrare la testa che è la risposta.

Pensavo che una risposta migliore potesse essere in grado di sfruttare la natura non deterministica degli Elenchi di Haskell attraverso l'uso di Applicazioni. Potrebbe essere possibile eliminare molti byte dalla funzione h utilizzando gli applicativi, anche se è necessario importare Control.Applicative. Commenti di miglioramento sono ben accetti.

Update1

Enormi risparmi basati sul promemoria di Laikoni sulla funzione minima. La rimozione dell'ordinamento in realtà mi ha permesso di eliminare l'importazione DataList perché il minimo è definito in Prelude!

UPDATE2

Grazie al suggerimento di nimi sull'uso della comprensione dell'elenco come un utile sostituto di filter.map. Questo mi ha salvato alcuni byte. Ho anche preso in prestito il trucco della partizione String dalla risposta di Laikonis e ho salvato anche un paio di byte lì.


1
h []=[[]]e h (x:y)=map ([x]:)contiene spazi bianchi non necessari. head.sortlo è minimum.
Laikoni,

@Laikoni Grazie! Aggiornerò quando torno sul mio computer!
maple_shaft

1
Un elenco di comprensione è spesso più breve di filter& map: g x=head$sort[length y|y<-h x,and$r<$>y].
nimi,

@nimi Grazie, ci sono così tanti consigli utili sul golf per Haskell. Imparo un nuovo trucco ogni volta.
maple_shaft

1

PHP, 319 byte

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;

Versione online

allargato

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

Versione più lunga senza E_NOTICE e output dell'array risultante


Questo sembra dare un risultato errato perababacabBACABABA
Zgarb

@Zgarb Ora funziona
Jörg Hülsermann
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.