JavaScriptで迷路の終点への経路を見つける方法
問題
N×N の正方行列で表される迷路が与えられます。壁は 'W'、通行可能な空きマスは '_' で表され、移動は上下左右の4方向がいつでも可能です。
この迷路の左上 [0, 0] からスタートし、右下の終点 [N - 1, N - 1] にたどり着けるかどうかを判定する JavaScript 関数を作成します。到達できる場合は true、できない場合は false を返します。
アプローチ:幅優先探索(BFS)
迷路のような「到達可能性」を求める問題には、幅優先探索(BFS)が適しています。キューを使って探索対象のマスを順番に処理しながら、訪問済みのマスを別の文字(ここでは '#')で上書きすることで、同じマスを二度探索しないようにします。
具体的な流れは以下のとおりです。
- スタート地点
[0, 0]をキューに入れる。 - キューが空になるまで、先頭の座標を取り出しては上下左右の隣接マスを確認する。
- 隣接マスが迷路の範囲内かつ空きマス(
'_')であれば、訪問済みを示す'#'に書き換えてキューに追加する。 - 探索終了後、終点
[N - 1, N - 1]が'#'になっていれば到達可能と判定する。
コード例
const maze = [
['_', 'W', 'W', 'W'],
['_', 'W', 'W', 'W'],
['W', '_', '_', 'W'],
['W', 'W', 'W', '_']
];
const canFindPath = (m = []) => {
const h = m.length; // 迷路の高さ(行数)
const w = m[0].length; // 迷路の幅(列数)
const queue = [[0, 0]]; // 探索待ちの座標を管理するキュー
while (queue.length) {
const [x, y] = queue.shift();
// 壁や訪問済みのマスはスキップ
if (m[y][x] !== '_') continue;
// 訪問済みとしてマーク
m[y][x] = '#';
// 上下左右の4方向を確認
for (const [dx, dy] of [[1, 0], [-1, 0], [0, 1], [0, -1]]) {
const nx = x + dx;
const ny = y + dy;
if (
nx >= 0 && nx < w &&
ny >= 0 && ny < h &&
m[ny][nx] === '_'
) {
queue.push([nx, ny]);
}
}
}
// 終点が訪問済みなら到達可能
return m[h - 1][w - 1] === '#';
};
console.log(canFindPath(maze));
出力結果
true
コードのポイント
- 座標の管理: 行列へのアクセスは
m[y][x]のように「行・列」の順で行うため、キューには[x, y](列, 行)の形式で座標を格納しています。 - 訪問管理: visited 配列を別途用意せず、元の行列自体を
'#'で書き換えることでメモリを節約できます。元のデータを保持したい場合は、関数に渡す前にコピーしましょう。 - 境界チェック:
nx・nyが迷路の範囲内にあるかを必ず確認し、配列外参照を防いでいます。 - 判定条件: 終点が
'#'に置き換わっていれば、そこへ至る経路が存在したことを意味します。
なお、元のコードでは空きマスの記号('_')と判定条件の記号('.')が一致しておらず、意図したとおりに動作しないケースがありました。本記事のコードではこの不整合を修正し、正しく動作するようになっています。
計算量
各マスは最大1回ずつ訪問されるため、時間計算量は O(N²)、キューと訪問マーク分の空間計算量も O(N²) です。迷路のサイズが大きくなっても線形に近い効率で処理できます。
-
JavaScriptでアルファベットの1始まりのインデックスを取得する方法
問題JavaScriptで関数を作成する必要があります。この関数は、小文字の英字アルファベット1文字を受け取り、その文字がアルファベットの中で何番目に位置するかを「1始まり」のインデックスとして返します。例えば、a なら 1、j なら 10 を返すといったイメージです。無効な入力が渡された場合は -1 を返してエラーを通知すると親切です。実装の考え方最もシンプルな方法は、先頭に半角スペースを付けたアルファベット文字列「 abcdefghijklmnopqrstuvwxyz」を基準(レジェンド)として用意することです。こうすることで、スペースが0番目となり、a は1番目、j は10番目というよう
-
【JavaScript】配列内で最も頻出する単語を上位N件抽出する方法
問題概要英小文字のみで構成された文字列の配列 arr を第一引数として受け取り、数値 num(num は配列の長さより小さい値)を第二引数として受け取る JavaScript 関数を作成します。この関数は、配列 arr 内で最も頻出する要素を上位 num 件返す必要があります。結果は出現回数が多い順に並べます。また、出現回数が同じ単語が複数ある場合は、辞書順(アルファベット順)で先に来る単語を優先して並べます。入力例const arr = [the, day, is, sunny, the, the, the, sunny, is, is]; const num = 4;出力例const ou