最後の位置を使って文字列をできるだけ多く切る

貪欲法問題 168

文字列を、どの文字も 1 つの切れにしか出ないように、できるだけ多くの切れに分けたときの切れの長さを返す。文字ごとに最後に出る位置を先に調べておけば、前から 1 回なめて切れ目を決められます。

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

問題

英小文字だけでできた文字列 s を受け取ります。s を前から順にいくつかの切れに分け、どの文字も 1 つの切れの中にしか出てこないようにします。そのような分け方のうち、切れの数が最も多い物を選び、切れの長さを前から順に並べて返す関数を書いてください。

  • 切れは、s を左から順に区切った物で、並べ替えや飛ばしはしません
  • 切れの数が最も多い分け方は 1 つに決まります
  • s の長さは 1 以上 500 以下です

入力と出力の例

例 1

a は 0 番と 3 番に出るので、abca は 1 つの切れに入ります。残りの d、e、ff、g はそれぞれ別の切れにできます。

s = "abcadeffg"
[4, 1, 1, 2, 1]

例 2

t は 0 番と 4 番、o は 1 番と 5 番に出るので、どこで切っても同じ文字が 2 つの切れに分かれます。全体で 1 つの切れです。

s = "tomato"
[6]

例 3

k は 1 回しか出ないので、そこで切れます。残りの iwi は i が両端に出るので 1 つの切れです。

s = "kiwi"
[1, 3]

面接での聞かれ方

面接では、短い一文で渡されることが多いです。

  • 「文字列を、同じ文字が別の切れに出ないように、できるだけ多く分けてください。切れの長さを返してください」
  • 「切れの中身ではなく長さを返すのですか」と確かめると、「長さで」と返ってくるのがふつうです
  • 書き終えたあとに「なぜこの切り方で切れの数が最も多くなるのですか」と、理由を聞かれることもあります

返すのが切れの長さか中身か、文字の種類は何かを、書く前に確かめておきます。

ヒント

まだ開いていません

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

  1. ヒント 2

  2. ヒント 3答えに近い

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

配列と文字列の問題は、全部の組を調べると手間が大きくなる所を、窓や左右の添字で減らす形が多いです。

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

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

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

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


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

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