問題
n 行 n 列のgrid を0 (通れる1 (ふさが
- 道が
無い ときは -1を返します。 左上か 右下が ふさが っている ときも -1です - n が 1 の
とき、 左上と 右下は 同じ マスです。 そこが 通れれば 答えは 1 です - n は 1 以上 100 以下です
入力と出力の例
例 1
下へ 1 歩、
入力
grid = [[0, 1, 1],
[0, 1, 1],
[1, 0, 0]]出力
4例 2
左上が
入力
grid = [[1, 0],
[0, 0]]出力
-1例 3
下へ、
入力
grid = [[0, 1, 0, 0],
[0, 1, 0, 1],
[0, 0, 1, 0],
[1, 1, 1, 0]]出力
6面接での聞かれ方
面接では、
- 「0 と 1 の
地図で、 左上から 右下までの 最短の 長さを 返してください」 - 書き終えた
あとに 「なぜ深さ優先では だめなのですか?」 「最初に 着いた 時が 最短だと 言える 理由は?」と 続けて 聞かれます - 「マスごとに
通る 手間が 違うなら、 どう 変えますか?」と、 重みの ある 最短の 道へ 広げて 聞かれる こともあります
長さを
アルゴリズムのチートシートの「グラフ探索と幅優先探索」に、この型の要点を表とコードでまとめています。
まず 考える手順
段 1
まずは、
段 2
どの
段 3
マスは、1 に
段 4
端の-1 を-1 で
解答
Python
Python
from collections import deque
STEPS = [
(-1, -1), (-1, 0), (-1, 1),
(0, -1), (0, 1),
(1, -1), (1, 0), (1, 1),
]
def shortest_path(grid):
n = len(grid)
if grid[0][0] == 1:
return -1
goal = (n - 1, n - 1)
grid[0][0] = 1
queue = deque([(0, 0, 1)])
push = queue.append
pop = queue.popleft
while queue:
r, c, d = pop()
if (r, c) == goal:
return d
for dr, dc in STEPS:
a = r + dr
b = c + dc
if not 0 <= a < n:
continue
if not 0 <= b < n:
continue
if grid[a][b] == 1:
continue
grid[a][b] = 1
push((a, b, d + 1))
return -1JavaScript
JavaScript
const STEPS = [
[-1, -1], [-1, 0], [-1, 1],
[0, -1], [0, 1],
[1, -1], [1, 0], [1, 1],
];
function shortestPath(grid) {
const n = grid.length;
if (grid[0][0] === 1) {
return -1;
}
grid[0][0] = 1;
const queue = [[0, 0, 1]];
let head = 0;
while (head < queue.length) {
const p = queue[head];
head++;
const [r, c, d] = p;
if (r === n - 1) {
if (c === n - 1) return d;
}
for (const s of STEPS) {
const a = r + s[0];
const b = c + s[1];
if (grid[a]?.[b] !== 0) {
continue;
}
grid[a][b] = 1;
queue.push([a, b, d + 1]);
}
}
return -1;
}Go
Go
var steps = [8][2]int{
{-1, -1}, {-1, 0}, {-1, 1},
{0, -1}, {0, 1},
{1, -1}, {1, 0}, {1, 1},
}
func shortestPath(
grid [][]int,
) int {
n := len(grid)
if grid[0][0] == 1 {
return -1
}
grid[0][0] = 1
queue := [][3]int{{0, 0, 1}}
head := 0
for head < len(queue) {
p := queue[head]
head++
r, c, d := p[0], p[1], p[2]
if r == n-1 && c == n-1 {
return d
}
for _, s := range steps {
a, b := r+s[0], c+s[1]
if a < 0 || a >= n {
continue
}
if b < 0 || b >= n {
continue
}
if grid[a][b] == 1 {
continue
}
grid[a][b] = 1
nx := [3]int{a, b, d + 1}
queue = append(queue, nx)
}
}
return -1
}JavaScript の grid[a]?.[b] は、undefined、undefined に0 以外をgrid を
計算量
- 時間は O(n²) です。
どの マスも 待ち行列に 1 回だけ 入って 1 回出て、 出る たびに 8 方向の 隣を 見るだけです - 使う
記憶は O(n²) です。 待ち行列に、 多い ときは マスの 数に 比例するだけ 並びます。 印は gridを書き換えて 付けるので、 別の 並びは 作りません
よく ある間違い
- 取り出す時に
印を付ける。 同じ マスが、 隣の いく つもの マスから 何度も 待ち行列に 入ります。 答えは 合っても 手間が ふくらみ、 大きな 地図で 時間切れに なります。 入れる 時に 印を付けます - 斜めを
忘れて 4 方向だけ見る。 例 1 では、 斜めに 進めないと 右下へ 着けず、 -1を返してしまいます。 8 方向を 並びに 書き出しておくと、 抜けに 気づきやすくなります - 歩数と
マスの 数を 取り違える。 左上から 数え 始める 値を 0 に すると、 答えが 1 つ 小さくなります。 左上を 1 マス目として 待ち行列に入れます - マスが 1 つで
ふさが っているのに 1 を返す。 n が 1 の とき、 左上と 右下は 同じ マスです。 「右下に着いたら返す」だけを 書くと、 その マスが ふさが っていても 1 を 返してしまいます。 左上が ふさが っているかを 最初に 確かめれば、 この 場合も -1で片付きます
解答を動かした版 Python 3.12.14Node.js 22.23.4Go 1.24.6確認日 2026年10月30日
面接での 話し方の例
書き始める
「1 歩の
重さが どれも 同じなので、 幅優先で 左上から 広げます。 待ち行列からは 近い マスから 順に 出るので、 右下を 最初に 取り出した 時の 長さが 最短です。 マスは 入れる 時に 印を 付け、 1 回しか 入れません。 時間も 記憶も O(n²) です。」
書き終えたら、
「例 1 で
たどります。 左上を 長さ 1 で 入れます。 取り出すと、 隣で 通れるのは 下の (1, 0) だけで、 長さ 2 で 入れます。 (1, 0) からは 斜め右下の (2, 1) だけが 長さ 3 で 入ります。 (2, 1) から 右の (2, 2) が 長さ 4 で 入り、 取り出した 時に 右下なので 4 を 返します。」
