バックトラックで文字列を回文だけに区切る方法を全部集める

文字列を、どの部分も前から読んでも後ろから読んでも同じ (回文) になるように区切る方法を、全部集めます。頭から 1 つ目の部分の長さを決めては残りを同じように区切る、を繰り返す練習です。

海外で定番の問題リスト 4 本には入っていません

問題

英小文字の文字列 s を受け取ります。s をいくつかの部分に切り分け、どの部分も回文 (前から読んでも後ろから読んでも同じ) になるようにします。そのような切り分け方を全部集めて、並びにして返す関数を書いてください。1 つの切り分け方は、部分の文字列を前から順に並べた並びで表します。

  • 1 字だけの部分は、いつも回文です。そのため、少なくとも 1 字ずつに切る方法は必ずあります
  • 切り分け方どうしの順は、1 つ目の部分が短い方を先にします。1 つ目が同じなら 2 つ目が短い方を先に、と後ろへ続けて比べます
  • s の長さは 1 以上 12 以下です

入力と出力の例

例 1

1 字ずつに切る方法、まん中の oo をまとめる方法、全体の noon をまとめる方法の 3 通りです。

s = "noon"
[["n", "o", "o", "n"], ["n", "oo", "n"], ["noon"]]

例 2

1 字なので、切り方は 1 通りです。

s = "x"
[["x"]]

例 3

aya と kayak も回文です。1 つ目が k の方法が先に 2 つ並び、最後に全体の kayak が来ます。

s = "kayak"
[["k", "a", "y", "a", "k"], ["k", "aya", "k"], ["kayak"]]

面接での聞かれ方

面接では、短く次のように渡されることが多いです。

  • 「文字列を、全部の部分が回文になるように分割する方法を全部返してください」
  • 書き終えると「回文かどうかを毎回確かめていますが、前もって表にできますか?」と、同じ判定の繰り返しを減らす工夫を聞かれます
  • 「分け方が何通りありうるか」から、最悪の計算量を言えるかも見られます

返す順と、1 字の部分も数えることを最初に確かめておくと、答えを 1 つに決められます。

ヒント

まだ開いていません

付箋は 4 枚。下の段ほど答えに近づきます

  1. ヒント 2

  2. ヒント 3

  3. ヒント 4答えに近い

アルゴリズムのチートシートの「再帰と木」に、この型の要点を表とコードでまとめています。

再帰は、同じ形の小さい問題に分けて自分を呼ぶ書き方です。木の深さや、全部の組み合わせを数える問題で使います。

main.py
def palindrome_parts(s: str) -> list[list[str]]:
    """
    Goal: 何を返すか

    idea1: まず思いつく案
    -> runtime: O(?)  space: O(?)

    idea2: もっと速い案
    -> runtime: O(?)  space: O(?)

    edge case: 空、1 つだけ、など
    """
    # ここに書きます
    pass


# 「実行」を押すと、この行の結果が出ます
print(palindrome_parts("noon"))

できているか「例で確かめる」を押すと、問題の例を全部この関数に渡して、通ったかをここに出します