動的計画法で 碁盤の 目の 左上から 右下への 道順を数える
碁盤の
海外で定番の問題リスト 4 本には入っていません
問題
縦 rows マス、cols マスの
- 左や
上へは 戻れません。 斜めにも 進めません - 通る
マスの 並びが 違えば、 別の 道順として数えます rowsとcolsは 1 以上 100 以下の整数で、 答えは 2 × 10^9 以下に なる ものとします
入力と出力の例
例 1
右へ 3 回、
例 2
右、
例 3
縦が 1 マスなら、
面接での聞かれ方
面接では、
- 「右か
下に しか 進めない とき、 左上から 右下への 道は 何通り ありますか」 - 書き終えると
「表を 1 行分の 並びに 減らせますか?」と続きます - 数学の
得意な 人には 「式 1 つで 出せますか?」と 聞かれる こともあります (組み合わせの 数で 出せます)
続けて
ヒント
まだ開いていません
付箋は 4 枚。下の段ほど答えに近づきます
ヒント 2
ヒント 3
ヒント 4答えに近い
アルゴリズムのチートシートの「動的計画法 (DP)」に、
関わる学び
動的計画法は、
まず 考える手順
段 1
道順を
段 2
ある
段 3
いちばん上の
段 4
1 cols 個のrow[c] += row[c-1] の 1 行で
解答
Python
Python
def grid_paths(rows, cols):
row = [1] * cols
for _ in range(rows - 1):
for c in range(1, cols):
row[c] += row[c - 1]
return row[cols - 1]JavaScript
JavaScript
function gridPaths(rows, cols) {
const m = rows;
const n = cols;
const row = Array(n).fill(1);
for (let r = 1; r < m; r++) {
let c = 1;
while (c < n) {
row[c] += row[c - 1];
c++;
}
}
return row[n - 1];
}Go
Go
func gridPaths(
rows, cols int,
) int {
row := make([]int, cols)
for c := range row {
row[c] = 1
}
for r := 1; r < rows; r++ {
for c := 1; c < cols; c++ {
row[c] += row[c-1]
}
}
return row[cols-1]
}始めの row は、row[0] は 1 のままc が 1 からrow[c]) とrow[c-1]) をm と n は、
計算量
- 時間は O(rows × cols) です。
表の マスを 1 つずつ埋めます - 使う
記憶は O(cols) です。 持つのは 1 行分の 並びだけです - 下へ
進む回数 rows - 1を、全部の 回数 rows + cols - 2から選ぶ組み合わせの 数として、 式で O(rows + cols) で 出すことも できます。 ただし途中の 掛け算が 大きくなるので、 割り算の 順を 気に する 必要があります
よく ある間違い
- マスの
数と 進む回数を 取り違える。 3 × 4 の 町で 進むのは 右へ 3 回、 下へ 2 回です。 右へ 4 回、 下へ 3 回と 数えると 35 に なってしまいます - 端の
行と 列を 0 で始める。 いちばん上の 行や いちばん左の 列を 0 に すると、 表の 全部が 0 に なります。 端は 1 通りです - 並び 1 本に
した とき、 右から 左へ埋める。 右から 埋めると、 左の マスが まだ前の 行の 値のままで、 上 + 左にならず 答えがずれます
解答を動かした版 Python 3.14.7Node.js 24.22.1Go 1.24.2確認日 2026年11月8日
面接での 話し方の例
書き始める
「ある
マスへ 来る 直前は、 上か左の マスです。 なので、 その マスの 道順は 上と 左の 数を 足した数です。 いちばん上の 行と いちばん左の 列は 1 通りです。 1 行ず つ埋めると、 使うのは 上の 行と 左だけなので、 並び 1 本で 足ります。 時間は O(rows × cols)、 記憶は O(cols) です。」
書き終えたら、
「例 1 の 3 × 4 で
たどります。 1 行目は 1、 1、 1、 1 です。 2 行目は 左から 1、 2、 3、 4、 3 行目は 1、 3、 6、 10 に なり、 右下は 10 です。」