Perfekte Palindrome

25

Ihre Aufgabe ist es, zu bestimmen, wie viel von einem perfekten Palindrom eine Zeichenfolge ist. Ihr typisches Palindrom (zB 12321) ist ein perfektes Palindrom; seine Vollkommenheit ist 1.

Um die Perfektion einer Zeichenfolge zu bestimmen, sehen Sie, in wie viele Abschnitte Sie sie aufteilen können, wobei jeder Abschnitt ein Palindrom ist. Wenn es Unklarheiten gibt, wie z. B. mit aaaa, wie Sie es in [aa, aa]oder [aaaa]oder [a, aaa]oder aufteilen können [aaa, a], hat die kürzeste Menge Vorrang und ergibt aaaaeine Punktzahl von 1, was der Länge der kürzesten Menge entspricht.

Aus diesem Grund müssen Sie ein Programm oder eine Funktion schreiben, die eine nicht leere Eingabe verwendet und ausgibt, wie perfekt sie ist (dies ist die Länge der kürzesten Menge, in die Sie sie aufteilen können, wobei jedes Element in der Menge ein Palindrom ist).

Beispiele:

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]

Beachten Sie, dass in den Beispielen alles in eckigen Klammern nicht Teil der Ausgabe sein sollte.

Okx
quelle
Ist die leere Zeichenfolge eine gültige Eingabe, und wenn ja, wie soll die Ausgabe lauten?
Zgarb
8
ababacabund sein Gegenteil bacababascheinen gute Testfälle zu sein.
Neil
@Neil sowie gute Argumente, ob ein linearer Zeitalgorithmus möglich ist.
Undichte Nonne
@Zgarb Leere Zeichenfolge ist keine gültige Eingabe.
Okx
ababacabBACABABAist auch ein guter Testfall (einige Antworten scheitern daran).
Zgarb

Antworten:

14

Brachylog , 7 Bytes

~cL↔ᵐLl

Probieren Sie es online!

Erläuterung

~cL          Deconcatenate the input into L
  L↔ᵐL       Reversing all elements of L results in L
     Ll      Output = length(L)
Tödlich
quelle
Du hast mich geschlagen ... auf meinem ersten Post lol
Leaky Nun
7
@LeakyNun Ich wusste, dass du es versuchen würdest. In den letzten Monaten konnte ich nachlassen und ein paar Stunden warten, jetzt mit dir zurück muss ich sofort antworten!
Fatalize
9

Jelly , 13 12 11 Bytes

ŒṖLŒṖ € P $ ÐfÐL 
ŒṖLŒṖ € ⁼ $ ÐfÐL
ŒṖṚ € ⁼ $ ÐfL € Ṃ
ŒṖ Partitionen erhalten
      Filter für Partitionen, die
  Ṛ € nach Umkehrung jeder Unterpartition
    ⁼ ist gleich der Partition
        L € Länge jeder erfolgreichen Partition
          Ṃ Minimum

Probieren Sie es online!

Technische Daten

  • Eingabe: "ababacab"(als Argument)
  • Ausgabe: 2
Undichte Nonne
quelle
3
@Okx naja du müsstest denen entkommen.
Undichte Nonne
2
Nun, ich denke nicht, dass es gültig ist, wenn es keine Backslashes akzeptieren kann.
Okx
14
@Okx Es ist, als würde man einen String schreiben. Sie können beispielsweise nicht erwarten, dass ein C-Programm mit einer Zeichenfolgeneingabe arbeitet "\", da dies eine ungültige Syntax ist.
Conor O'Brien
2
Willkommen zurück, übrigens. :-)
Arnauld
2
Leider gibt dies unterschiedliche Antworten für ababacabund sein Gegenteil bacababa.
Neil
6

Pyth, 9 Bytes

lh_I#I#./

Testsuite

Dies bildet alle Partitionen der Eingabe, von der kürzesten bis zur längsten. Dann filtert es diese Partitionen nach Invarianz unter Filtern der Elemente nach Invarianz unter Umkehrung. Schließlich nehmen wir das erste Element der gefilterten Partitionsliste und geben dessen Länge zurück.

Um diesen komplizierten Schritt zu erklären, lassen Sie sich mit Invarianz unter Umkehrung beginnen: _I. Dadurch wird überprüft, ob es sich bei der Eingabe um ein Palindrom handelt, da überprüft wird, ob durch Umkehren der Wert geändert wird.

Als nächstes Filterung für palindromicity: _I#. Dadurch bleiben nur die palindromischen Elemente der Liste erhalten.

Als nächstes überprüfen wir für Invarianz Filterung für palindromicity: _I#I. Dies ist nur dann wahr, wenn alle Elemente der Liste Palindrome sind.

Schließlich haben wir für Listen filtern , wo alle Elemente der Liste sind Palindrome: _I#I#.

isaacg
quelle
Ich muss noch viel lernen ...
Undichte Nonne
6

Haskell , 83 Bytes

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

Probieren Sie es online!

Hierbei wird Zgarbs großartiger Tipp zum Generieren von Zeichenfolgenpartitionen verwendet .

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
quelle
1
Wow! Das hat mich umgehauen! Ich muss definitiv viel lernen.
maple_shaft
5

Clojure, 111 Bytes

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

Teilt an allen möglichen Positionen, und wenn der erste Teil ein Palindrom ist, sucht er nach einer Unterteilung für den verbleibenden Teil der Zeichenfolge.

Probieren Sie es online aus .

Ungolfed, verwendet Thread-Last-Makro ->> .

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

Eine obskure Version, bitte schreibe keinen Code wie diesen: 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
quelle
Würde dieser Tipp helfen? Ich kenne Clojure überhaupt nicht.
Undichte Nonne
Normalerweise ja, aber in diesem Fall muss sich die Funktion finnerhalb des for: aufrufen (f b). Auf einer Tail-Call-Position können Sie verwenden recur.
NikoNyrh
Sie können immer noch ersetzen defnmit fnund nur eine Funktion haben.
Cliffroot
(fn f[s]( ... ))? Oh, das ist wahr. Sie sparen damit 2 Zeichen.
NikoNyrh
5

JavaScript (ES6), 143 126 124 Byte

2 Bytes gespart dank Neil

Inspiriert von der NikoNyrh- Methode.

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)

Formatiert und kommentiert

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

Testfälle


Anfängliche Ansatz 173 168 Bytes

Eine ziemlich lange rekursive Funktion, die alle möglichen Partitionen der Eingabezeichenfolge berechnet.

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)

Formatiert und kommentiert

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

Testfälle

Arnauld
quelle
Wenn ich Ihre Erklärung richtig verstanden haben, können Sie ein paar Bytes speichern verwendet ,p=0, s[p++]?und ,F(s,i,p).
Neil
@ Neil Ja in der Tat. :-)
Arnauld
5

Gelee , 10 Bytes

ŒṖŒḂ€¬$ÞḢL

Probieren Sie es online!

Wie?

Verwendet die Tatsache, dass
[0]<[0,0]<[0,0,0],...,<[0,...,0,1]<...
- wenn wir also die Partitionen nach einem Schlüssel sortieren "ist nicht für jeden Teil palindromisch", der erste Eintrag alle palindromisch und von minimaler Länge ist.

Hinweis: Eine nicht leere Zeichenfolge der Länge n führt immer zu einem solchen Schlüssel mit n Nullen, da alle Zeichenfolgen der Länge 1 palindrom sind.

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

Haskell , 69 Bytes

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

Definiert eine Funktion f. Probieren Sie es online!

Erläuterung

Die Infix-Hilfsfunktion x ! yberechnet eine Liste von Ganzzahlen, die die Länge einiger Aufteilungen reverse x ++ yin Palindrome sind, bei denen reverse xsie intakt bleiben. Es ist garantiert, dass die Länge der minimalen Aufteilung enthalten ist, wenn sie ynicht leer ist. Wie es funktioniert ist dies.

  • Wenn yes nicht leer ist, wird ein Zeichen entfernt und hineingeschoben x. Wenn xein Palindrom wird, rufen wir die Hauptfunktion fam Ende von auf yund addieren 1, um dies zu berücksichtigen x. Auch wir fordern !das Neue auf xund yverpassen keine mögliche Spaltung.
  • Wenn yleer ist, geben wir zurück [0](eine Aufteilung der Länge 0), wenn xebenfalls leer ist, und [](keine Aufteilungen), wenn nicht.

Die Hauptfunktion fruft nur auf "" ! xund nimmt das Minimum der Ergebnisse.

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

ES6-Port:

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>

Es scheint eine so einfache Lösung zu sein, dass ich immer wieder denke, ich habe etwas vergessen, aber es besteht zumindest alle Testfälle.

Neil
quelle
1

Haskell, 139 116 109 Bytes

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]

Immer noch grün bei Haskell Golf, aber hier ist mein bester Versuch, den ich schnell finden kann.

  • h ist eine Funktion, die eine Liste aller möglichen aufeinander folgenden Teilfolgen einer Liste erstellt (wie eine Zeichenfolge). Es nimmt den eingegebenen String und bricht ihn für g auf.
  • r ist eine einfache Funktion, die einen Booleschen Wert zurückgibt, wenn eine Liste ein Palindrom ist
  • g ist die Hauptfunktion, die eine Eingabeliste aufnimmt, h aufruft, um die Liste der zusammenhängenden Teilsequenzmöglichkeiten abzurufen, nach filtert (and.map r), um Teillisten zu entfernen, die kein Palindrom enthalten. Ab diesem Zeitpunkt wird die Liste mit der folgenden Länge versehen: sortiert, damit wir den Kopf greifen können, der die Antwort ist.

Ich dachte, eine bessere Antwort könnte den nicht deterministischen Charakter von Listen in Haskell durch die Verwendung von Anwendern nutzen. Es ist möglicherweise möglich, mithilfe von Anwendern viele Bytes der Funktion h zu entfernen, selbst wenn Control.Applicative importiert werden muss. Verbesserungsvorschläge sind willkommen.

UPDATE1

Riesige Einsparungen aufgrund der Erinnerung von Laikoni an die Mindestfunktion. Durch das Entfernen der Sortierung konnte ich den Data.List-Import tatsächlich löschen, da das Minimum in Prelude!

UPDATE2

Dank Nimis Vorschlag, Listenverständnisse als nützlichen Ersatz für filter.map zu verwenden. Das hat mir ein paar Bytes erspart. Außerdem habe ich mir von Laikonis answer den netten String-Partitionstrick ausgeliehen und dort auch ein paar Bytes gespart.

maple_shaft
quelle
1
h []=[[]]und h (x:y)=map ([x]:)unnötigen Leerraum enthalten. head.sortist minimum.
Laikoni,
@Laikoni Danke! Ich werde aktualisieren, wenn ich wieder auf meinem Computer bin!
maple_shaft
1
Eine Liste Verständnis ist oft kürzer als filter& map: g x=head$sort[length y|y<-h x,and$r<$>y].
Nimi
@nimi Danke, es gibt so viele nützliche Golftipps für Haskell. Ich lerne jedes Mal einen neuen Trick.
maple_shaft
1

PHP, 319 Bytes

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;

Online Version

Erweitert

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

Längere Version ohne E_NOTICE und Ausgabe des resultierenden Arrays

Jörg Hülsermann
quelle
Dies scheint ein falsches Ergebnis zu ababacabBACABABA
liefern
@Zgarb Jetzt funktioniert es
Jörg Hülsermann