動的計画法で 売った 次の 日は 買えない 決まりの 売り 買いの 利益を 最大にする
毎日の
海外で定番の問題リスト 4 本には入っていません
問題
あるprices でprices[i] は i 日目の
- 1 日に、
買うか 売るか 何もしないかの どれか 1 つだけをします - 持てる
品物は 1 つまでです。 持っている 間は 買えず、 持っていなければ 売れません - 売った
次の 日は 休みで、 買えません (その次の 日からは 買えます) - 売り
買いは 何回してもかまいません。 1 回もしなければ 利益は 0 です pricesの長さは 1 以上 5000 以下で、 どの 値段も 0 以上 1000 以下の整数です
入力と出力の例
例 1
0 日目に 4 で
例 2
休みが
例 3
値段が
面接での聞かれ方
面接では、
- 「何回でも
売り 買いできますが、 売った 翌日は 買えません。 最大の 利益は?」 - 最初に
「同じ 日に 売って 買えますか?」 「休みは 売った 次の 1 日だけですか?」と 確かめられるかを 見られます - 書き終えると
「状態の 移り方を 図で 説明してください」と 言われる ことがあります
日ごとに
ヒント
まだ開いていません
付箋は 4 枚。下の段ほど答えに近づきます
ヒント 2
ヒント 3
ヒント 4答えに近い
アルゴリズムのチートシートの「動的計画法 (DP)」に、
関わる学び
動的計画法は、
まず 考える手順
段 1
毎日
段 2
あるhold)、sold)、rest)。
段 3
今日の
holdは、前から 持っていた (前の hold) か、休みでない 日から 今日買った (前の restから x を引く ) の 大きいほう soldは、前に 持っていた 物を 今日売った (前の holdに x を足す)restは、前も restか、前の 日に 売った (前の sold。今日が 休みの 日) の 大きいほう
前のsold からは、
段 4
始めはhold はsold と rest は 0 です。sold と rest の
解答
Python
Python
def cooldown_profit(prices):
hold = -10**9
sold = 0
rest = 0
for x in prices:
prev_hold = hold
buy = rest - x
hold = max(hold, buy)
rest = max(rest, sold)
sold = prev_hold + x
return max(sold, rest)JavaScript
JavaScript
function cooldownProfit(
prices,
) {
let hold = -1e9;
let sold = 0;
let rest = 0;
for (const x of prices) {
const prevHold = hold;
const buy = rest - x;
hold = Math.max(hold, buy);
rest = Math.max(rest, sold);
sold = prevHold + x;
}
return Math.max(sold, rest);
}Go
Go
func cooldownProfit(
prices []int,
) int {
hold := -1000000000
sold := 0
rest := 0
for _, x := range prices {
prevHold := hold
buy := rest - x
hold = max(hold, buy)
rest = max(rest, sold)
sold = prevHold + x
}
return max(sold, rest)
}書き換えるhold はrest からbuy をrest をrest はsold をsold をsold はhold をprevHold に
計算量
- 時間は O(n) です (n は
日数)。 1 日ずつ 1 回見ます - 使う
記憶は O(1) です。 持つのは 3 つの 状態だけです - 日ごとに 3 つの
状態の 表を 全部持つ 書き方も 時間は 同じで、 記憶が O(n) になります
よく ある間違い
- 売った
次の 日に 買えるように してしまう。 holdを前の soldから作ると 休みの 決まりが 消え、 例 2 で 9 を返します - 書き換えの
順を誤る。 restを先に 書き換えてから holdを求めると、 今日売ったばかりの 利益で 今日買えたことになります。 3 つとも 前の 日の 値から 作られているかを 確かめます - 値の
上がる 日を 全部足す。 休みの 無い 問題なら それで 合いますが、 この 問題では 上がった 日を つなぐと 休みの 日に 買うことが あり、 例 2 のように 多すぎる 答えになります
解答を動かした版 Python 3.14.7Node.js 24.22.1Go 1.24.2確認日 2026年11月8日
面接での 話し方の例
書き始める
「日の
終わりの 状態を、 持っている、 今日売った、 何も 持たず 休んでいる、の 3 つに 分けます。 持っているは 前から 持っていたか 休みの 状態から 買ったか、 今日売ったは 前に 持っていた 物を 売る、 休んでいるは 前も 休みか前の 日に 売ったかです。 売った 次の 日は 買えないので、 売った 状態からは 直接買いに 移りません。 時間は O(n)、 記憶は O(1) です。」
書き終えたら、
「例 2 の
[2, 6, 3, 8]でたどります。 0 日目は 持っているが -2 です。 1 日目は 今日売ったが 4 に なります。 2 日目は、 休んでいるが 4 に なります。 持っているは、 前の 日の 休んでいる 0 から 3 で 買う -3 より、 -2 のままが 大きいです。 3 日目は 今日売ったが -2 + 8 で 6、 休みは 4 なので 答えは 6 です。」