動的計画法で最大と最小の積を持ち歩き、積が最大の続いた区間を求める

負の数と 0 を含む整数の並びから、続いた区間の積のうち最も大きい値を求めます。負の数を掛けると大小が入れ替わるので、そこで終わる区間の最大と最小を 2 つ並べて持ち歩く練習です。

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

問題

整数の並び nums を受け取ります。nums の続いた区間 (1 つ以上の要素) の積のうち、いちばん大きい値を返す関数を書いてください。

  • 区間は 1 つ以上の要素を含みます。空の区間は選べません
  • nums の長さは 1 以上 1000 以下で、どの値も -10 以上 10 以下の整数です
  • nums の先頭から、または末尾からのどの区間の積も、-2^31 以上 2^31 未満に収まるものとします

入力と出力の例

例 1

負の数が 2 つあるので、全部を掛けると正の 24 になります。

nums = [2, -3, -4, 1]
24

例 2

全部を掛けると負の数が 3 つで -60 です。最後の 3 つ [4, -1, -5] の 20 がいちばん大きくなります。

nums = [3, -1, 4, -1, -5]
20

例 3

0 をまたぐ区間の積は 0 です。負の数だけの区間はどれも 0 より小さいので、0 だけの区間の 0 が答えです。

nums = [-2, 0, -1]
0

面接での聞かれ方

面接では、最大部分配列和 (和が最大の区間) を解いた人への続きとして出されます。

  • 「続いた区間の積が最大になる値を返してください」
  • 和の書き方をそのまま積に替えて書くと、「負の数が 2 つあったら?」と聞き返されます
  • 「0 があったら?」「全部が負なら?」と、端の場合を順に聞かれることが多いです

和と違って、悪い値 (いちばん小さい負の数) が次の 1 歩で最大に化けるのが、この問題の芯です。

ヒント

まだ開いていません

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

  1. ヒント 2

  2. ヒント 3

  3. ヒント 4答えに近い

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

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

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

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

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

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


# 「実行」を押すと、この行の結果が出ます
print(max_product([2, -3, -4, 1]))

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