📋 問題概要
ロボットがm×nグリッドの左上角(0,0)から右下角(m-1,n-1)に移動する際の、 一意な経路数を計算する問題です。
- ロボットは右または下にのみ移動可能
- 制約: 1 ≤ m, n ≤ 100
- 結果は 2 × 10⁹ 以下が保証
🧮 数学的解法 (最適解)
💡 核心アイデア
この問題は組み合わせ数学の問題として解けます。
ロボットは合計 (m-1) + (n-1) = m+n-2 回移動し、
そのうち右に n-1 回、下に m-1 回移動します。
これは「m+n-2回の移動のうち、右移動(または下移動)の回数を選ぶ組み合わせ」として表現できます。
⚡ 実装コード
import math
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
"""
数学的解法による経路数計算
Time: O(1), Space: O(1)
"""
# 組み合わせ数 C(m+n-2, min(m-1, n-1))
total_moves = m + n - 2
right_moves = n - 1
down_moves = m - 1
# math.comb()はPython 3.8+のC実装で高速
return math.comb(total_moves, min(right_moves, down_moves))
def uniquePathsManual(self, m: int, n: int) -> int:
"""
手動実装版(Python 3.7以下対応)
"""
total_moves = m + n - 2
k = min(m - 1, n - 1)
result = 1
for i in range(k):
result = result * (total_moves - i) // (i + 1)
return result
📊 計算例: m=3, n=7
計算過程:
📈 1次元動的プログラミング
💡 核心アイデア
2次元DPの空間計算量を最適化し、O(min(m,n))まで削減。 前の行の情報のみを保持することで実現します。
⚡ 実装コード
def uniquePathsDP1D(self, m: int, n: int) -> int:
"""
1次元DPによる実装
Time: O(m×n), Space: O(min(m,n))
"""
# メモリ効率化: 小さい方の次元で配列作成
cols = min(m, n)
rows = max(m, n)
# DPテーブル初期化
dp = [1] * cols
# 各行を処理
for i in range(1, rows):
for j in range(1, cols):
# dp[j] = 上から + 左から
dp[j] += dp[j - 1]
return dp[cols - 1]
🎯 可視化デモ
📋 2次元動的プログラミング
💡 核心アイデア
最も直感的な解法。各セル(i,j)への経路数は、
dp[i][j] = dp[i-1][j] + dp[i][j-1] で計算。
⚡ 実装コード
def uniquePaths2D(self, m: int, n: int) -> int:
"""
2次元DPによる実装
Time: O(m×n), Space: O(m×n)
"""
# 2次元DPテーブル初期化
dp = [[0] * n for _ in range(m)]
# 初期化: 最初の行と列は全て1
for i in range(m):
dp[i][0] = 1
for j in range(n):
dp[0][j] = 1
# DPテーブル更新
for i in range(1, m):
for j in range(1, n):
dp[i][j] = dp[i-1][j] + dp[i][j-1]
return dp[m-1][n-1]
🎯 可視化デモ
📊 アルゴリズム比較分析
⚖️ 計算量比較
| 解法 | 時間計算量 | 空間計算量 | 可読性 | 実装難易度 |
|---|---|---|---|---|
| 数学的解法 | O(1) | O(1) | 高 | 低 |
| 1次元DP | O(m×n) | O(min(m,n)) | 中 | 中 |
| 2次元DP | O(m×n) | O(m×n) | 最高 | 低 |
🚀 パフォーマンステスト
パフォーマンステストを実行してください
💡 選択指針
数学的解法 推奨
- 競技プログラミング
- 高速処理が必要
- メモリ制約が厳しい
1次元DP 推奨
- メモリ効率重視
- DPの学習目的
- 拡張性が必要
2次元DP 推奨
- 教育・学習目的
- 可読性最優先
- デバッグが必要
🎯 まとめ
📈 学習ポイント
- 問題の抽象化: 格子経路問題を組み合わせ数学で解く
- 空間計算量最適化: 2次元→1次元DPへの変換
- 数学的洞察: 動的プログラミングを数式で置き換え
- 実装選択: 用途に応じた最適解法の選択
🔧 実装のコツ
- 境界条件: 最初の行・列の初期化
- オーバーフロー対策: 整数演算の順序に注意
- メモリ最適化: 必要最小限のデータ構造使用
- 型安全性: 適切な型ヒントの活用