JavaScriptのバックトラッキングパターンで解くアルゴリズム問題:全マスを通るユニークパスの総数
今回は、バックトラッキング(Backtracking)パターンを使って解く典型的なアルゴリズム問題を、JavaScriptで実装してみましょう。
2次元グリッド上には、次の4種類のマスが存在します。
- 1:スタート地点のマス(必ず1つだけ存在する)
- 2:ゴール地点のマス(必ず1つだけ存在する)
- 0:自由に移動できる空きマス
- -1:障害物(通行できないマス)
実装する関数は、スタートからゴールまで「上下左右の4方向移動」だけで進み、かつ障害物以外のすべてのマスをちょうど1回ずつ通過する経路の総数を返すものです。
例
const arr = [
[1,0,0,0],
[0,0,0,0],
[0,0,2,-1]
];
const uniquePaths = (arr, count = 0) => {
const dy = [1,-1,0,0], dx = [0,0,1,-1];
const m = arr.length, n = arr[0].length;
const totalZeroes = arr.map(row => row.filter(num => num === 0).length)
.reduce((sum, next) => sum + next, 0);
const depthFirstSearch = (i, j, covered) => {
if (arr[i][j] === 2){
if (covered === totalZeroes + 1) count++;
return;
}
for (let k = 0; k < 4; k++)
if (i+dy[k] >= 0 && i+dy[k] < m && j+dx[k] >= 0 && j+dx[k] < n
&& arr[i+dy[k]][j+dx[k]] !== -1){
arr[i][j] = -1;
depthFirstSearch(i+dy[k], j+dx[k], covered+1);
arr[i][j] = 0;
}
return;
};
for (let row = 0; row < m; row++)
for (let col = 0; col < n; col++)
if (arr[row][col] === 1){
arr[row][col] = -1;
depthFirstSearch(row, col, 0);
break;
}
return count;
};
console.log(uniquePaths(arr));
コードの解説
- 事前準備:移動方向を表す配列 dy・dx を用意して、上下左右への反復処理をシンプルにします。あわせてグリッド内の空きマス(0)の総数を数えておき、再帰のベースケースに達したときに「すべてのマスを訪れたかどうか」を判定できるようにしています。
- DFSとバックトラッキング:depthFirstSearch の中では、現在のマスを -1 でマークして「この経路ですでに通過済み」であることを示します。4方向それぞれについて、グリッドの範囲内かつ障害物でなければ再帰的に探索を進め、呼び出しから戻ったらマークを 0 に復元します。この「マーク → 探索 → 復元」の一連の流れこそがバックトラッキングの核心です。ゴール(2)に到達した時点で、訪問カウンター covered が totalZeroes + 1 と一致していれば、全マスを漏れなく通った完全な経路としてカウントします。
- 探索の開始:最後にスタートマスを探して -1 に設定し、そこから DFS を起動します。条件を満たすすべての経路を数え上げ、その合計を返り値として返します。
出力
コンソールには次のように表示されます。
2
補足:なぜバックトラッキングが適しているのか
この問題は「すべてのマスをちょうど1回ずつ訪れる」という強い制約があるため、単純な動的計画法では解けません。各ステップで4方向に分岐しながら行き止まりまで掘り下げ、失敗すれば直前の状態へ巻き戻して別の道を試す——バックトラッキングは、こうした全経路の列挙に最も適した手法です。最悪の時間計算量は O(4^(m×n)) ですが、障害物や訪問済みマスによる枝刈りの効果で、実際の探索範囲は大きく絞り込まれます。
-
JavaScriptのdebuggerステートメントの使い方を徹底解説
JavaScriptのdebuggerステートメントは、コード内にブレークポイントを設定するための構文です。実行中のコードがdebuggerステートメントに到達すると、その時点で処理が一時停止し、開発者ツールのデバッガーが利用可能であれば自動的にデバッガー機能が呼び出されます。 debuggerステートメントの基本動作 debuggerステートメントは、以下のような場面で特に役立ちます。 コードの特定の箇所で処理を止めて、変数の値を確認したいとき ループ処理の各ステップを詳細に追跡したいとき 複雑なロジックの不具合原因を特定したいとき なお、ブラウザの開発者ツール(DevTools)が開い
-
JavaScriptで数字パターンを表示する方法【初心者向けサンプルコード】
本記事では、テキスト入力欄とボタンを備えたJavaScript・HTMLプログラムの作成方法を解説します。ユーザーが入力欄に任意の数値(例:5)を入力してボタンをクリックすると、画面に以下のような数字パターンが表示される仕組みです。(n = 5 の場合の出力例)01 01 02 01 02 03 01 02 03 04 01 02 03 04 05仕組みのポイントこのパターンは二重ループ(ネストしたforループ)を使うことで実現できます。外側のループが「行」を制御し、内側のループがその行に表示する「数字の個数」を制御します。i 行目には 1 から i までの数字が順番に出力されるため、行が進む