行列90度回転: 転置 + 行反転アルゴリズム解析
1. アルゴリズム概要
このアルゴリズムは2段階のアプローチを採用します:
- Step 1: 行列を転置(対角線に対して反転)
- Step 2: 各行を左右反転
この2つの操作を組み合わせることで、90度時計回りの回転を実現します。
2. Step 1: 転置(Transpose)の詳細解析
転置の概念
転置とは、行列の行と列を入れ替える操作です。要素 matrix[i][j] が
matrix[j][i] と交換されます。
for (let i = 0; i < n; i++) { for (let j=i + 1; j < n; j++) {
const temp:
number = matrix[i][j]; matrix[i][j] = matrix[j][i];
matrix[j][i] = temp;
} }
⚠️ 重要なポイント: なぜ j = i + 1 から?
理由:
対角線より上の部分のみを処理することで、各要素ペアを1回だけ交換
もし j = 0 から始めると:
同じ要素ペアを2回交換してしまい、元に戻ってしまう
対角線要素: matrix[i][i] は交換不要(自分自身との交換)
3×3行列での転置デモンストレーション
初期状態:
処理対象: 対角線より上の要素のみ
交換ペア: (0,1)↔(1,0), (0,2)↔(2,0), (1,2)↔(2,1)
→
転置後:
結果: 行と列が入れ替わった
対角線要素(1,5,9)は変化なし
転置処理の詳細な反復解析
3. Step 2: 行反転(Reverse Rows)の詳細解析
行反転の実装
for (let i = 0; i < n; i++) { matrix[i].reverse();
}
行反転のデモンストレーション
→
各行反転後(最終結果):
各行の変化:
[1,4,7] → [7,4,1]
[2,5,8] → [8,5,2]
[3,6,9] → [9,6,3]
4. 完全なアルゴリズムデモンストレーション
4×4行列での完全な処理過程
5. なぜこの方法で90度回転になるのか?
数学的説明
(i, j) → (j, i)
(j, i) → (j, n-1-i)
(i, j) → (j, n-1-i)
例: 4×4行列での座標変換
• 元の(0,1) → 転置後(1,0) → 行反転後(1,3) ✓
• 元の(2,0) → 転置後(0,2) → 行反転後(0,1) ✓
• 元の(3,2) → 転置後(2,3) → 行反転後(2,0) ✓
6. 計算量分析
時間計算量: O(n²)
Step 1 (転置): n×n要素の約半分を処理 → O(n²/2) = O(n²)
Step 2 (行反転): n行 × 各行n/2要素 → O(n²/2) = O(n²)
合計: O(n²) + O(n²) = O(n²)
空間計算量: O(1)
転置: 一時変数temp のみ使用
行反転: Array.reverse() はin-place操作
総メモリ: 追加配列不要、定数空間のみ
7. アルゴリズム比較
転置+行反転の利点
- 実装が直感的で理解しやすい
- 2つの単純な操作の組み合わせ
- デバッグが容易
- Array.reverse()の最適化を活用
- コードが短くて読みやすい
レイヤー回転との比較
- 2回の配列走査が必要
- キャッシュ効率が若干劣る可能性
- reverse()の内部実装に依存
結論:
実用的には性能差は僅少で、コードの可読性が重要な場合は優秀な選択
8. 実装時の注意点
よくある間違いとその対策
-
転置で全要素を処理 → 要素が元に戻る(j = i+1 から開始)
- 型エラー → TypeScriptでは適切な型注釈が必要
- reverse()の返り値 → 元配列を変更し、その参照を返す
- 境界条件 → n=1の場合も正しく動作することを確認