完美回文


25

您的任务是确定一个字符串有多少完美的回文。您的典型回文(例如12321)是一个完美的回文。完美是1。

要确定字符串的完美性,您可以看到可以将其分成多少部分,每个部分都是回文。如果存在歧义,例如with aaaa,可以将其拆分为[aa, aa]or [aaaa][a, aaa]or [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]

请注意,在示例中,方括号中的任何内容均不应成为输出的一部分。


空字符串是有效输入吗?如果是,则输出应该是什么?
Zgarb

8
ababacab反之,bacababa似乎是很好的测试案例。
尼尔

@Neil以及关于线性时间算法是否可能的良好论据。
Leaky Nun

@Zgarb空字符串无效输入。
Okx

ababacabBACABABA也是一个很好的测试用例(一些答案失败了)。
Zgarb

Answers:


14

Brachylog,7个字节

~cL↔ᵐLl

在线尝试!

说明

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

您击败了我...在我的第一则帖子哈哈
Leaky Nun

7
@LeakyNun我知道您会尝试的。上个月,我可以放松一下,等待几个小时,现在和您一起回来,我必须立即回答!
Fatalize

9

果冻13 12 11字节

ŒṖLPP$ 
ÐfḢLŒṖLÞṚL⁼P$ÐfḢL
Ð$ÐfL€Ṃ
ŒṖ获取分区
      Ðf过滤器用于分区
  反转每个子分区后
    ⁼等于分区
        每个成功分区的长度
          Ṃ最低

在线尝试!

眼镜

  • 输入:("ababacab"作为参数)
  • 输出: 2

3
@Okx好,您将不得不逃避那些。
Leaky Nun

2
好吧,如果它不能接受反斜杠,我认为这是无效的。
Okx

14
@Okx就像写一个字符串。例如,您不能期望C程序可以使用字符串输入"\",因为这是无效的语法。
Conor O'Brien

2
顺便欢迎您回来。:-)
Arnauld

2
可悲的是,这给出了不同的答案,ababacab反之亦然bacababa
尼尔

6

Pyth,9个字节

lh_I#I#./

测试套件

这将形成输入的所有分区,从最短到最长。然后,它在逆转条件下过滤不变性元素时,对那些不变性分区进行过滤。最后,我们获取分区过滤列表的第一个元素,并返回其长度。

为了说明这一复杂的步骤,让我们从反转下的不变性开始:_I。这会检查其输入是否为回文,因为它会检查反转是否会更改值。

接着,对于过滤palindromicity: _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]

在线尝试!

这使用Zgarb的绝妙技巧来生成字符串分区

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

在所有可能的位置分割,并且当第一部分是回文时,继续查找其余字符串的分区。

在线尝试

取消高尔夫,使用线程最后的宏 ->>

(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必须在for:中调用自身(f b)。在尾叫位置,您可以使用recur
NikoNyrh

您仍然可以替换defnfn并仅具有一个功能。
悬崖根

(fn f[s]( ... ))?哦,是的。您可以保存2个字符。
NikoNyrh

5

JavaScript(ES6),143 126 124字节

感谢Neil,节省了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=0s[p++]?,F(s,i,p)
尼尔

@Neil是的。:-)
Arnauld

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为非空,则会从其弹出一个char并将其推入x。如果x成为回文,我们f在的尾部调用main函数,y并为加上1 x。此外,我们呼吁!采用新技术xy不要错过任何潜在的分裂。
  • 如果y为空,则返回[0](长度为0的一个分割),如果x也为空,则返回[](无分割)。

main函数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是一个创建List的所有可能连续子序列(如字符串)的List的函数。它接受输入的String并将其分解为g。
  • r是一个简单函数,如果列表是回文,则返回布尔值
  • g是接收输入List的主要函数,调用h获取连续子序列可能性的列表,使用on过滤(and.map r)以除去不包含回文的子列表,在该点上将长度应用于该列表,然后结果是排序,这样我们就可以抓住答案的头。

我在想更好的答案可能是通过使用Applicatives来利用Haskell中List的不确定性。即使我们必须导入Control.Applicative,也可能通过使用应用程序将函数h削减很多字节。欢迎提出改进意见。

更新1

根据Laikoni关于最低功能的提醒,可节省大量资金。删除排序实际上使我可以删除Data.List导入,因为在Prelude中定义了最小值!

更新2

感谢nimi关于使用列表推导作为filter.map的有用替代方法的建议。那节省了我几个字节。我还从Laikonis答案中借用了整洁的String分区技巧,并在那里也保存了几个字节。


1
h []=[[]]h (x:y)=map ([x]:)包含不必要的空格。head.sortminimum
Laikoni '17

@Laikoni谢谢!当我回到计算机时,我将进行更新!
maple_shaft

1
列表理解通常比filtermap:短g x=head$sort[length y|y<-h x,and$r<$>y]
nimi

@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它的工作原理
约尔格Hülsermann
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.