Pythonで階段の登り方の総数を求めるプログラムを作成する方法
プログラミングの典型的な問題として、「階段の登り方」問題があります。この記事では、Pythonを使ってこの問題を動的計画法(DP)で解く方法を詳しく解説します。
問題の概要
n段の階段があるとします。一度に1段または2段ずつ上ることができる場合、この階段を上るユニークな登り方の総数を返す関数を定義する必要があります。
ポイントは、段を踏む順序が異なれば別の登り方としてカウントするという点です。また、答えが非常に大きな数になる可能性があるため、結果を 10^9 + 7 で割った余りを返します。
例えば、入力が n = 5 の場合、出力は 8 となります。これは、次の8通りのユニークな登り方が存在するためです。
- 1, 1, 1, 1, 1
- 2, 1, 1, 1
- 1, 2, 1, 1
- 1, 1, 2, 1
- 1, 1, 1, 2
- 1, 2, 2
- 2, 1, 2
- 2, 2, 1
解法のアプローチ:動的計画法(DP)
この問題はフィボナッチ数列と同じ構造を持っています。i 番目の段に到達する方法の数は、「i-1 番目から1段で来る方法」と「i-2 番目から2段で来る方法」の合計になります。以下の手順で解きます。
- サイズ
n+1の配列dpを作成し、すべて0で初期化する dp[1] = 1を設定する(1段目への登り方は1通り)i = 2からn+1まで繰り返し処理を行い、dp[i] = dp[i-1] + dp[i-2]を計算する- 配列
dpの最後の要素をmで割った余りを返す
実装例
それでは、実際のPythonコードを見てみましょう。
m = (10**9) + 7
class Solution:
def solve(self, n):
dp = [0 for _ in range(n+2)]
dp[1] = 1
for i in range(2, n+2):
dp[i] = dp[i-1] + dp[i-2]
return dp[-1] % m
ob = Solution()
print(ob.solve(5))
入力
5
出力
8
まとめ
このように、階段の登り方の総数を求める問題は、動的計画法を用いることで効率的に解くことができます。時間計算量はO(n)、空間計算量もO(n)であり、n段の階段に対して線形時間で計算可能です。この手法は、フィボナッチ数列に関連するさまざまな組み合わせ最適化問題にも応用できるので、ぜひ覚えておきましょう。
-
Pythonで捕まえられる雨水の総量を計算するプログラム(トレッピング・レイン・ウォーター問題)
非負整数からなる長さ n の配列が与えられているとします。各要素はバーの高さを表し、それぞれのバーの幅は1です。このとき、雨が降った後に溜め込むことのできる水の総量を計算するのが本記事のテーマです。状況を図にすると、以下のようになります。図を見ると、水が溜まっている部分(青い箱)は全部で8個あります。したがって、このケースの出力は8となります。解法のアプローチこの問題は「スタック」を利用することで効率よく解けます。全体の手順は以下の通りです。スタック st、変数 water := 0、インデックス i := 0 を用意するi が高さ配列のサイズ未満である間、次の処理を繰り返すスタックが空である
-
Pythonで二分木を2つの木に分割できるパターン数を数えるプログラム
問題の概要値「0」「1」「2」を含む二分木があるとします。根(ルート)には、少なくとも1つの「0」ノードと1つの「1」ノードが存在しています。ここで、「木の辺(エッジ)を1本削除すると、木が2つの異なる木に分割される」という操作を考えます。このとき、削除後に生成される2つの木のどちらにも「0」と「1」のノードが同時に含まれないように、辺を1本削除する方法が何通りあるかを求めるのがこの問題です。入力例例えば、次のような二分木が与えられたとします。この場合、出力は 1 となります。「0」から「2」へ向かう辺だけが、条件を満たす唯一の削除対象だからです。解法のアプローチこの問題は、DFS(深さ優先探