区間の動的計画法で最後に割る風船を決め、得点の合計を最大にする

並んだ風船を 1 つずつ割り、割った風船と左右の隣の数の積を得点にするとき、合計の最大を求めます。区間の中で「最後に割る風船」を決めて、左右を別々の小さな区間に分ける練習です。

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

問題

一列に並んだ風船に、整数が 1 つずつ書いてあります。並び nums で受け取り、nums[i] は左から i 番目の風船の数です。風船を 1 つずつ、好きな順で全部割ります。風船を割ると、その風船の数と、そのとき左右の隣にある風船の数の 3 つを掛けた値が得点になります。得点の合計のいちばん大きい値を返す関数を書いてください。

  • 割った風船は列から消え、その左右の風船が新しく隣どうしになります
  • 左か右に風船が残っていないときは、そちらの数を 1 として掛けます
  • nums の長さは 1 以上 100 以下で、どの数も 0 以上 100 以下の整数です

入力と出力の例

例 1

まん中の 1 を先に割ると 9 × 1 × 9 で 81、次に左の 9 を割ると 1 × 9 × 9 で 81、最後の 9 で 1 × 9 × 1 の 9 です。合わせて 171 です。

nums = [9, 1, 9]
171

例 2

2 を先に割って 4 × 2 × 6 で 48、次に 4 を割って 1 × 4 × 6 で 24、最後の 6 で 6 です。合わせて 78 です。

nums = [4, 2, 6]
78

例 3

風船が 1 つなら、左右とも 1 を掛けて 5 です。

nums = [5]
5

面接での聞かれ方

面接では、区間を分けて考える動的計画の代表として、難しめの枠で出されます。

  • 「風船を割る順を決めて、得点の合計を最大にしてください」
  • 「最初に割る風船」で分けようとして詰まった所で、「最後に割る風船で考えたら?」と促されることがあります
  • 書き終えると「表を埋める順は?」「計算量は?」と聞かれます

最初に割る風船で分けると、左右の区間が割った後につながってしまい、別々に考えられません。考える向きを逆にできるかが見どころです。

ヒント

まだ開いていません

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

  1. ヒント 2

  2. ヒント 3

  3. ヒント 4答えに近い

アルゴリズムのチートシートの「動的計画法 (DP)」に、この型の要点を表とコードでまとめています。

動的計画法は、途中の答えを覚えておいて、同じ計算をやり直さない書き方です。漸化式で言い直せる問題が多いです。

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

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

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

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


# 「実行」を押すと、この行の結果が出ます
print(max_burst([9, 1, 9]))

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