パーフェクトパリンドローム


25

あなたの仕事は、文字列がどれだけ完璧な回文であるかを決定することです。あなたの典型的な回文(例12321)は完全な回文です。その完全性は1です。

文字列の完全性を判断するために、各セクションが回文である場所に分割できるセクション数を確認します。withなどのあいまいさが存在する場合、or またはorにaaaa分割できるため、最短セットがオーバーライドされ、最短セットの長さであるスコア1が与えられます。[aa, aa][aaaa][a, aaa][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および線形時間アルゴリズムが可能かどうかに関する適切な引数。
リーキー修道女

@Zgarb空の文字列は有効な入力ではありません。
Okx

ababacabBACABABA良いテストケースでもあります(いくつかの答えは失敗します)。
-Zgarb

回答:


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)

あなたは私の最初の投稿で私を打ち負かしたlol
Leaky Nun

7
@LeakyNunあなたが試してみることを知っていました。先月、私は怠けて数時間待つことができましたが、あなたと一緒にすぐに答えなければなりません!
致命的

9

ゼリー13 12 11バイト

ŒṖLÞŒḂ€P $ÐfḢLŒṖLÞṚ 
€⁼$ÐfḢL
€⁼$ÐfL€Ṃ
partitionsパーティションを取得する
      パーティションのÐfフィルタ
  sub€各サブパーティションを反転した後
    ⁼はパーティションに等しい
        成功した各パーティションの長さ
          Ṃ最小

オンラインでお試しください!

スペック

  • 入力:("ababacab"引数として)
  • 出力: 2

3
@Okxよくそれらをエスケープする必要があります。
リーキー修道女

2
まあ、バックスラッシュを受け入れられないなら有効だとは思わない。
Okx

14
@Okx文字列を書くようなものです。たとえば、Cプログラムが文字列input "\"で動作することは期待できません。これは無効な構文だからです。
コナーオブライエン

2
ところで、おかえりなさい。:
アーナルド

2
悲しいことに、これは異なる答えababacabとその逆を与えbacababaます。
ニール

6

Pyth、9バイト

lh_I#I#./

テストスイート

これは、最短から最長まで、入力のすべてのパーティションを形成します。次に、反転下の不変性の要素をフィルタリングすることで、不変性のパーティションをフィルタリングします。最後に、フィルタリングされたパーティションのリストの最初の要素を取得し、その長さを返します。

その複雑なステップを説明するために、反転の下での不変性から始めましょう_I。これは、入力が回文であるかどうかをチェックします。これは、反転によって値が変更されるかどうかをチェックするためです。

次に、回文性のフィルタリング:_I#。これにより、リストの回文要素のみが保持されます。

次に、回文性のフィルタリングの下で​​不変性をチェックします_I#I。これは、リストのすべての要素が回文である場合にのみ真実です。

最後に、リストのすべての要素が回文であるリストをフィルタリングします_I#I#


私は...学ぶことがたくさん持っている
漏れ修道女

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

すべての可能な位置で分割し、最初の部分が回文である場合、残りの文字列のパーティション分割を見つけます。

オンラインでお試しください

Ungolfed、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.

あいまいなバージョン、このようなコードを書かないでください: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をまったく知りません。
リーキー修道女

通常、はい。ただし、この場合、関数fはfor:内で自分自身を呼び出す必要があります(f b)。末尾呼び出し位置では、を使用できますrecur
ニコニール

あなたはまだ置き換えることができdefnfn、ちょうど機能を持っています。
クリフルート

(fn f[s]( ... ))?そうそう。それで2文字を保存します。
ニコニール

5

JavaScriptの(ES6)、143の 126 124バイト

ニールのおかげで2バイト節約

ニコニール法に触発されました

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はい、そうです。:
アーナルド

5

ゼリー、10 バイト

ŒṖŒḂ€¬$ÞḢL

オンラインでお試しください!

どうやって?

つまり
[0]<[0,0]<[0,0,0],...,<[0,...,0,1]<...
、キーでパーティションを「各部分に対して回文的ではない」ようにソートすると、最初のエントリはすべて回文的で最小の長さになります。

注:すべての長さ1の文字列は回文的であるため、長さnの空ではない文字列は常に、n個のゼロを持つそのようなキーになります。

ŒṖŒḂ€¬$ÞḢ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空で、文字はそれからポップとに押し込まれますxx回文になった場合はf、末尾のmain関数を呼び出してy、に1を加えますx。また、私たち!は新しいものxy求め、潜在的な分割を見逃さないようにします。
  • yが空の場合、空の場合[0](長さ0の1つの分割)を返しx[]それ以外の場合(分割なし)を返します。

メイン関数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

ハスケル、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は、リストの可能なすべての連続したサブシーケンスのリストを作成する関数です(文字列など)。入力文字列を取得し、gに分割します。
  • rは、リストが回文である場合にブール値を返す単純な関数です
  • gは、入力リストを取得し、hを呼び出して連続(and.map r)するサブシーケンスの可能性のリストを取得するメイン関数です。フィルターを使用して、パリンドロームを含まないサブリストを削除します。ソートされているので、答えである頭をつかむことができます。

私は、より適切な答えが、Applicativeの使用を通じてHaskellのリストの非決定論的な性質を活用できるかもしれないと考えていました。Control.Applicativeをインポートする必要がある場合でも、applicativesを使用して、関数hから多くのバイトを削ることができる場合があります。改善のためのコメントを歓迎します。

更新1

ライコニの最小関数に関するリマインダーに基づく大幅な節約。プレリュードで最小値が定義されているため、ソートを削除すると、実際にData.Listインポートを削除できました。

更新2

filter.mapの便利な代替としてリスト内包表記を使用することについてのnimiの提案に感謝します。それで数バイト節約できました。また、私はライコニスの答えからきちんとした文字列パーティションのトリックを借りて、そこにも数バイトを保存しました。


1
h []=[[]]そしてh (x:y)=map ([x]:)、不要な空白が含まれています。head.sortですminimum
ライコニ

@ライコニありがとう!コンピューターに戻ったら更新します!
maple_shaft

1
リスト内包は、多くの場合、より短いですfiltermapg 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動作するようになりました
ヨルクヒュルサーマン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.