Palindromes hoàn hảo


25

Nhiệm vụ của bạn là xác định bao nhiêu chuỗi palindrom hoàn hảo. Bảng màu điển hình của bạn (ví dụ 12321) là một bảng màu hoàn hảo; sự hoàn hảo của nó là 1.

Để xác định sự hoàn hảo của một chuỗi, bạn xem có bao nhiêu phần bạn có thể chia nó thành nơi mỗi phần là một bảng màu. Nếu có sự mơ hồ, chẳng hạn như với aaaa, như bạn có thể chia nó thành [aa, aa]hay [aaaa]hay [a, aaa]hay [aaa, a], tập ngắn nhất sẽ ghi đè lên, cho aaaamột điểm số 1, đó là độ dài của tập ngắn nhất.

Do đó, bạn phải viết một chương trình hoặc hàm sẽ lấy một đầu vào không trống và đầu ra hoàn hảo đến mức nào (đó là độ dài của tập ngắn nhất mà bạn có thể chia nó thành nơi mỗi phần tử trong tập hợp là một bảng màu).

Ví dụ:

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]

Lưu ý rằng trong các ví dụ, mọi thứ trong ngoặc vuông không nên là một phần của đầu ra.


Chuỗi rỗng có phải là đầu vào hợp lệ không và nếu có thì đầu ra phải là gì?
Zgarb

8
ababacabvà ngược lại của nó bacababa, dường như là trường hợp thử nghiệm tốt.
Neil

@Neil cũng như các lập luận tốt về việc liệu thuật toán thời gian tuyến tính có khả thi hay không.
Leaky Nun

@Zgarb Chuỗi rỗng không phải là đầu vào hợp lệ.
Okx

ababacabBACABABAcũng là một trường hợp thử nghiệm tốt (một số câu trả lời thất bại về nó).
Zgarb

Câu trả lời:


14

Brachylog , 7 byte

~cL↔ᵐLl

Hãy thử trực tuyến!

Giải trình

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

Bạn đánh bại tôi ... trên bài đăng đầu tiên của tôi lol
Leaky Nun

7
@LeakyNun Tôi biết bạn sẽ thử nó. Tháng trước tôi có thể buông lơi và chờ đợi một vài giờ, bây giờ với bạn trở lại tôi phải trả lời ngay lập tức!
Gây tử vong vào

9

Thạch , 13 12 11 byte

ŒṖLÞŒḂ € P $ ĐfḢL 
LÞṚ € $ ĐfḢL
ŒṖṚ € ⁼ $ ĐfL €
Có được phân vùng
      Bộ lọc Ðf cho các phân vùng
  € sau khi đảo ngược từng phân ngành
    Bằng với phân vùng
        Chiều dài L € của mỗi phân vùng thành công
          Tối thiểu

Hãy thử trực tuyến!

Thông số kỹ thuật

  • Đầu vào: "ababacab"(như đối số)
  • Đầu ra: 2

3
@Okx tốt bạn sẽ phải thoát khỏi những.
Leaky Nun

2
Chà, tôi không nghĩ nó hợp lệ nếu nó không thể chấp nhận dấu gạch chéo ngược.
Okx

14
@Okx Nó giống như viết một chuỗi. Bạn không thể mong đợi, giả sử, một chương trình C hoạt động với đầu vào chuỗi "\", vì đó là cú pháp không hợp lệ.
Conor O'Brien

2
Nhân tiện chào mừng trở lại. :-)
Arnauld

2
Đáng buồn thay điều này cho câu trả lời khác nhau cho ababacabvà ngược lại của nó , bacababa.
Neil

6

Bình thường, 9 byte

lh_I#I#./

Bộ kiểm tra

Điều này tạo thành tất cả các phân vùng của đầu vào, từ ngắn nhất đến dài nhất. Sau đó, nó lọc các phân vùng trên bất biến dưới lọc các phần tử trên bất biến dưới sự đảo ngược. Cuối cùng, chúng tôi lấy phần tử đầu tiên của danh sách các phân vùng được lọc và trả về độ dài của nó.

Để giải thích bước phức tạp đó, chúng ta hãy bắt đầu với bất biến dưới sự đảo ngược : _I. Điều đó kiểm tra xem đầu vào của nó có phải là một bảng màu hay không, bởi vì nó kiểm tra xem việc đảo ngược có làm thay đổi giá trị hay không.

Tiếp theo, lọc cho palindromility : _I#. Điều này sẽ chỉ giữ lại các yếu tố palindromic của danh sách.

Tiếp theo, chúng tôi kiểm tra tính bất biến trong quá trình lọc để kiểm tra tính độc hại : _I#I. Điều này là đúng nếu và chỉ khi tất cả các yếu tố của danh sách là palindromes.

Cuối cùng, chúng tôi lọc các danh sách trong đó tất cả các thành phần của danh sách là palindromes : _I#I#.


Tôi có rất nhiều điều để học ...
Leaky Nun

6

Haskell , 83 byte

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

Hãy thử trực tuyến!

Điều này sử dụng mẹo tuyệt vời của Zgarb để tạo phân vùng chuỗi .

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
Ồ Điều này đã thổi vào tâm trí của tôi! Tôi chắc chắn có rất nhiều để học hỏi.
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)))

Tách tại tất cả các vị trí có thể, và khi phần đầu tiên là một palindrom tiến hành tìm phân vùng cho phần còn lại của chuỗi.

Hãy thử trực tuyến .

Ungolfed, sử dụng macro cuối cùng ->> .

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

Một phiên bản tối nghĩa, xin vui lòng không viết mã như thế này: 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)))

Mẹo này sẽ giúp? Tôi hoàn toàn không biết Clojure.
Leaky Nun

Thường thì có, nhưng trong trường hợp này, hàm fphải gọi chính nó trong for : (f b). Trên một vị trí gọi đuôi bạn có thể sử dụng recur.
NikoNyrh

Bạn vẫn có thể thay thế defnbằng fnvà chỉ có một chức năng.
vách đá

(fn f[s]( ... ))? Ồ đúng rồi. Bạn lưu 2 ký tự với điều đó.
NikoNyrh

5

JavaScript (ES6), 143 126 124 byte

Đã lưu 2 byte nhờ Neil

Lấy cảm hứng từ phương pháp 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)

Định dạng và nhận xét

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

Các trường hợp thử nghiệm


Cách tiếp cận ban đầu, 173 168 byte

Một hàm đệ quy khá dài tính toán tất cả các phân vùng có thể có của chuỗi đầu vào.

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)

Định dạng và nhận xét

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

Các trường hợp thử nghiệm


Nếu tôi đã hiểu lời giải thích của bạn một cách chính xác, bạn có thể tiết kiệm một vài byte sử dụng ,p=0, s[p++]?,F(s,i,p).
Neil

@Neil Vâng thực sự. :-)
Arnauld

5

Thạch , 10 byte

ŒṖŒḂ€¬$ÞḢL

Hãy thử trực tuyến!

Làm sao?

Sử dụng thực tế là
[0]<[0,0]<[0,0,0],...,<[0,...,0,1]<...
- do đó, nếu chúng ta sắp xếp các phân vùng theo một khóa "không phải là palindromic cho mỗi phần", mục nhập đầu tiên sẽ là tất cả các palindromic và có độ dài tối thiểu.

Lưu ý: bất kỳ chuỗi không trống nào có độ dài n sẽ luôn dẫn đến một khóa như vậy với n số không, vì tất cả các chuỗi có độ dài 1 đều là palindromic.

ŒṖŒḂ€¬$ÞḢ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.(""!)

Xác định một hàm f. Hãy thử trực tuyến!

Giải trình

Hàm trợ giúp infix x ! ytính toán một danh sách các số nguyên, là độ dài của một số mối nối reverse x ++ yvào palindromes nơi reverse xcòn nguyên vẹn. Nó được đảm bảo để chứa độ dài của phần tách tối thiểu nếu ykhông trống. Làm thế nào nó hoạt động là thế này.

  • Nếu ykhông trống, một char được bật ra và đẩy vào x. Nếu xtrở thành một palindrom, chúng ta gọi hàm chính fở đuôi yvà thêm 1 vào tài khoản x. Ngoài ra, chúng tôi kêu gọi !mới xykhông bỏ lỡ bất kỳ sự chia tách tiềm năng nào.
  • Nếu ytrống, chúng tôi trả về [0](một lần chia độ dài 0) nếu xcũng trống và [](không có mối nối) khác.

Hàm chính fchỉ gọi "" ! xvà lấy kết quả tối thiểu.

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

Cổng 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>

Có vẻ như một giải pháp đơn giản đến nỗi tôi cứ nghĩ rằng mình đã quên một điều gì đó nhưng ít nhất nó cũng vượt qua tất cả các trường hợp thử nghiệm.


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]

Vẫn còn xanh ở sân golf Haskell nhưng đây là nỗ lực tốt nhất của tôi để tôi có thể nhanh chóng đạt được.

  • h là một hàm tạo ra một Danh sách tất cả các chuỗi liền kề có thể có của Danh sách (như một chuỗi). Nó lấy Chuỗi đầu vào và ngắt nó ra cho g.
  • r là một hàm đơn giản trả về Boolean nếu Danh sách là một bảng màu
  • g là hàm chính lấy Danh sách đầu vào, gọi h để lấy danh sách các khả năng tiếp theo liền kề, bộ lọc (and.map r)để xóa danh sách phụ không chứa bảng màu, tại đó độ dài điểm được áp dụng cho danh sách, và sau đó kết quả là sắp xếp để chúng ta có thể lấy đầu đó là câu trả lời.

Tôi đã suy nghĩ một câu trả lời tốt hơn có thể có thể thúc đẩy bản chất không xác định của Danh sách trong Haskell thông qua việc sử dụng Ứng dụng. Có thể loại bỏ nhiều byte khỏi chức năng h bằng cách sử dụng các ứng dụng, ngay cả khi chúng ta phải nhập Control.Applicative. Bình luận để cải thiện được chào đón.

CẬP NHẬT1

Tiết kiệm rất lớn dựa trên lời nhắc của Laikoni về chức năng tối thiểu. Loại bỏ sắp xếp thực sự cho phép tôi bỏ nhập Data.List vì mức tối thiểu được xác định trong Mở đầu!

CẬP NHẬT2

Nhờ đề xuất của nimi về việc sử dụng tính năng hiểu danh sách như một sự thay thế hữu ích cho bộ lọc.map. Điều đó đã tiết kiệm cho tôi một vài byte. Ngoài ra, tôi đã mượn thủ thuật phân vùng String gọn gàng từ câu trả lời Laikonis và cũng lưu một vài byte ở đó.


1
h []=[[]]h (x:y)=map ([x]:)chứa khoảng trắng không cần thiết. head.sortminimum.
Laikoni

@Laikoni Cảm ơn! Tôi sẽ cập nhật khi tôi quay lại máy tính của mình!
maple_shaft

1
Một sự hiểu biết danh sách thường ngắn hơn filter& map: g x=head$sort[length y|y<-h x,and$r<$>y].
nimi

@nimi Cảm ơn bạn, có rất nhiều mẹo chơi golf hữu ích cho Haskell. Tôi học được một mẹo mới mọi lúc.
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;

Phiên bản trực tuyến

Mở rộng

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

Phiên bản dài hơn không có E_NOTICE và xuất ra mảng kết quả


Điều này dường như đưa ra một kết quả không chính xác choababacabBACABABA
Zgarb

@Zgarb Bây giờ nó hoạt động
Jörg Hülsermann
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.