動的計画法 (DP) で階段の上り方を数える

1 段か 2 段ずつ上るとき、n 段の階段の上り方が何通りあるかを数える。小さな段の答えを覚えて使い回す、動的計画の最初の練習です。

海外で定番の問題リスト 4 本のうち 4 本に入っています (Blind 75、NeetCode 150、Grind 75、LeetCode Top Interview 150)

問題

n 段の階段を、1 回に 1 段か 2 段ずつ上ります。いちばん上まで上る上り方が何通りあるかを返す関数を書いてください。

  • 上る順が違えば、別の上り方として数えます。たとえば「1 段、2 段」と「2 段、1 段」は別です
  • n は 1 以上 45 以下の整数です

入力と出力の例

例 1

「1、1、1、1」「1、1、2」「1、2、1」「2、1、1」「2、2」の 5 通りです。

n = 4
5

例 2

n = 5
8

例 3

1 段だけなら、1 段上る 1 通りです。

n = 1
1

面接での聞かれ方

面接では、次のように渡されることが多いです。

  • 「階段を 1 段か 2 段ずつ上ります。n 段の上り方は何通りですか」
  • 再帰で書くと「n が 45 だと、どのくらい時間がかかりますか?」と続けて聞かれます
  • 「1 回に 3 段まで上れるとしたら?」と、決まりを変えて聞かれることもあります

数え方を決める前に、小さな n を手で数えて、答えの並びを先に見ておくと、決まりに気づきやすくなります。

ヒント

まだ開いていません

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

  1. ヒント 2

  2. ヒント 3

  3. ヒント 4

  4. ヒント 5答えに近い

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

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

main.py
def climb_ways(n: int) -> int:
    """
    Goal: 何を返すか

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

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

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


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

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