動的計画法で 通行料つきの 階段を いちばん安く上る
段ごとに
海外で定番の問題リスト 4 本には入っていません
問題
階段のcost でcost[i] は i 段目の
- 始めは 0 段目か 1 段目の
どちらかに、 料金を 払わずに立てます - 料金は、
その 段から 進むときに 払います。 立っただけでは 払いません costの長さは 2 以上 1000 以下で、 どの 料金も 0 以上 999 以下の整数です
入力と出力の例
例 1
0 段目から
例 2
1 段目から
例 3
2 段しかない
面接での聞かれ方
面接では、
- 「段ごとに
料金が あります。 いちばん上まで 最も 安く 上ると、 いくらですか」 - 最初に
「ゴールは 最後の 段ですか、 その 1 つ上ですか?」 「始めの 段の 料金は 払いますか?」と 確かめられるかを 見られます - 書き終えると
「表を 使わずに、 記憶を O(1) に できますか?」と続きます
ゴールの
ヒント
まだ開いていません
付箋は 4 枚。下の段ほど答えに近づきます
ヒント 2
ヒント 3
ヒント 4答えに近い
アルゴリズムのチートシートの「動的計画法 (DP)」に、
関わる学び
動的計画法は、
まず 考える手順
段 1
全部の
段 2
「i 段目にbest[i] とbest[i] は best[i-1] + cost[i-1] と best[i-2] + cost[i-2] の
段 3
始めは 0 段目と 1 段目にbest[0] と best[1] は 0 です。best[n] (n は
段 4
best[i] を
解答
Python
Python
def stair_cost(cost):
two, one = 0, 0
n = len(cost)
for i in range(2, n + 1):
a = one + cost[i - 1]
b = two + cost[i - 2]
two = one
one = min(a, b)
return oneJavaScript
JavaScript
function stairCost(cost) {
let two = 0;
let one = 0;
const n = cost.length;
for (let i = 2; i <= n; i++) {
const a = one + cost[i - 1];
const b = two + cost[i - 2];
two = one;
one = Math.min(a, b);
}
return one;
}Go
Go
func stairCost(cost []int) int {
two, one := 0, 0
n := len(cost)
for i := 2; i <= n; i++ {
a := one + cost[i-1]
b := two + cost[i-2]
two = one
one = min(a, b)
}
return one
}one と two は、best[i-1] と best[i-2] です。a は 1 つ下のb は 2 つ下のone が best[n] で、
計算量
- 時間は O(n) です (n は
段の 数)。 どの 段も 1 回ずつ見ます - 使う
記憶は O(1) です。 持つのは 2 つの 変数だけです bestの表を 全部持つ 書き方も 時間は 同じで、 記憶が O(n) になります
よく ある間違い
- 最後の
段を ゴールにする。 答えを best[n-1]にすると、 最後の 段の 料金を 払わずに 済ませた ことになります。 例 3 で 0 を 返したら、 この 間違いです - 始めの
段の 料金を 先に払う。 best[0] = cost[0]と置くと、 立っただけで 払った ことに なり、 料金を 2 回数える 道ができます - 安い段を
欲張りで選ぶ。 始めに 安い ほうの 段に 立ち、 次の 2 段の うち安い ほう へ進む 決め方は 外れます。 cost = [1, 2, 9, 1, 100]では、0 段目から 1、 2、 1 と 払って 4 に なります。 1 段目から 始めて 2 と 1 を 払う 3 が答えです
解答を動かした版 Python 3.14.7Node.js 24.22.1Go 1.24.2確認日 2026年11月8日
面接での 話し方の例
書き始める
「i 段目に
立つまでの 最も 安い合計を 考えると、 直前は i - 1 段目か i - 2 段目で 料金を 払ったかの どちらかです。 なので 2 つの 候補の 安い ほうを 取ります。 0 段目と 1 段目は 無料で 0、 ゴールは 最後の 段の 1 つ上です。 使うのは 前の 2 つだけなので、 時間は O(n)、 記憶は O(1) です。」
書き終えたら、
「例 1 の
[3, 8, 2, 9, 1]でたどります。 0 段目と 1 段目は 0、 2 段目は 0 + 8 と 0 + 3 の 安い ほうで 3、 3 段目は 3 + 2 と 0 + 8 で 5、 4 段目は 5 + 9 と 3 + 2 で 5、 上へ 抜けるのは 5 + 1 と 5 + 9 で 6 です。」