深さ優先探索 (DFS) で グリッドの いちばん 大きい島の 広さを求める
陸と
海外で定番の問題リスト 4 本には入っていません
問題
海のgrid で1 (陸) か 0 (海) です。
- 斜めに
隣り合うだけの 陸は、 つながっていない ものとします - 地図の
外側は、 すべて 海だと考えます - 行の
数と 列の 数は、 どちらも 1 以上 50 以下です。 どの 行も 同じ長さです - 関数の
中で gridを書き換えてかまいません
入力と出力の例
例 1
左上の
例 2
陸が
例 3
斜めに
面接での聞かれ方
面接では、
- 「0 と 1 の
グリッドで、 1 が つながった 島の うち、 いちばん 大きい島の 面積を 返してください」 - 島の
数を 数える 問題の あとに、 続けて 出される ことが 多い 問題です。 「島の 数の コードから、 どこを 変えましたか?」と 聞かれます - 書き終えると
「再帰で 書くと、 地図が 大きいとき 何が 起きますか?」と、 呼び出しの 深さを 聞かれる ことがあります
斜めの
ヒント
まだ開いていません
付箋は 4 枚。下の段ほど答えに近づきます
ヒント 2
ヒント 3
ヒント 4答えに近い
アルゴリズムのチートシートの「グラフ探索と幅優先探索」に、
関わる学び
グラフ探索は、
まず 考える手順
段 1
全部の
段 2
島を
段 3
同じ陸を 2 回数えないように、0) に
段 4
再帰で
解答
Python
Python
def max_island_area(grid):
h = len(grid)
w = len(grid[0])
return max(
fill(grid, r, c)
for r in range(h)
for c in range(w))
STEPS = ((1, 0), (-1, 0),
(0, 1), (0, -1))
def fill(grid, r, c):
# 陸を海に塗りながら数える
if grid[r][c] == 0:
return 0
grid[r][c] = 0
todo = [(r, c)]
area = 0
while todo:
r, c = todo.pop()
area += 1
for dy, dx in STEPS:
y = r + dy
x = c + dx
if land(grid, y, x):
grid[y][x] = 0
todo += [(y, x)]
return area
def land(grid, y, x):
if not 0 <= y < len(grid):
return False
row = grid[y]
if not 0 <= x < len(row):
return False
return row[x] == 1JavaScript
JavaScript
function maxIslandArea(grid) {
let best = 0;
grid.forEach((row, r) => {
row.forEach((_, c) => {
best = Math.max(
best, fill(grid, r, c));
});
});
return best;
}
// 陸を海に塗りながら数える
function fill(grid, r, c) {
if (grid[r][c] === 0) {
return 0;
}
const h = grid.length;
const w = grid[0].length;
grid[r][c] = 0;
const todo = [[r, c]];
let area = 0;
while (todo.length) {
const [y, x] = todo.pop();
area++;
for (const [ny, nx] of [
[y + 1, x], [y - 1, x],
[y, x + 1], [y, x - 1],
]) {
if (ny < 0 || ny >= h ||
nx < 0 || nx >= w) {
continue;
}
if (grid[ny][nx] === 1) {
grid[ny][nx] = 0;
todo.push([ny, nx]);
}
}
}
return area;
}Go
Go
var dirs = [][2]int{
{1, 0}, {-1, 0},
{0, 1}, {0, -1},
}
func maxIslandArea(
grid [][]int,
) int {
best := 0
for r := range grid {
for c := range grid[r] {
a := fill(grid, r, c)
best = max(best, a)
}
}
return best
}
// 陸を海に塗りながら数える
func fill(
grid [][]int, r, c int,
) int {
if grid[r][c] == 0 {
return 0
}
h := len(grid)
w := len(grid[0])
grid[r][c] = 0
todo := [][2]int{{r, c}}
area := 0
for len(todo) > 0 {
p := todo[len(todo)-1]
todo = todo[:len(todo)-1]
area++
for _, d := range dirs {
y := p[0] + d[0]
x := p[1] + d[1]
if y < 0 || y >= h ||
x < 0 || x >= w {
continue
}
if grid[y][x] == 1 {
grid[y][x] = 0
todo = append(todo,
[2]int{y, x})
}
}
}
return area
}fill は、max に
計算量
- 時間は O(m × n) です。
m と n は 行と 列の 数です。 どの マスも、 外の 繰り返しで 1 回、 塗りつぶしで 多くて 1 回積まれ、 上下左右の 4 つを 見るだけです - 使う
記憶は O(m × n) です。 全部が 陸なら、 スタックに マスが たくさん 積まれます
よく ある間違い
- 取り出すときに塗る。
同じ マスが 別の 隣から 何度も 積まれ、 広さを 多く 数えます。 積むときに塗ります - 島の
数を返す。 島の 数の 問題と 形が 似ているので、 数えた 広さではなく 島の 数を 返してしまうことがあります。 返すのは いちばん 広い島の広さです - 陸が
無い ときに困る。 いちばん 広い値を 0 から 始めれば、 陸が 無い ときも そのまま 0 を返せます - 範囲を
確かめる 前に マスを読む。 Python は 負の 番号で 反対の 端を 読んでしまい、 別の 島と つながったと数えます
解答を動かした版 Python 3.14.7Node.js 24.22.1Go 1.24.2確認日 2026年11月8日
面接での 話し方の例
書き始める
「全部の
マスを 順に 見て、 陸を 見つけたら、 そこから スタックで 深さ優先に たどって 島の 広さを 数えます。 積むときに 海に 塗るので、 同じ マスを 2 回数えません。 島ごとの 広さの いちばん 大きい値を 返します。 どの マスも 数回しか 見ないので、 時間は O(m × n) です。」
書き終えたら、
「例 1 では、
左上の 陸から 始めて、 右、 下、 右と 4 マスた どって 広さ 4 です。 次に 見つかるのは 右上の 1 マスで 広さ 1、 最後に 右下の 3 マスで 広さ 3 です。 いちばん 広い 4 を 返します。」