行列90度時計回り回転アルゴリズム解析
1. アルゴリズム概要
このアルゴリズムはレイヤーベースの4要素同時回転を使用します。行列を同心円状のレイヤーに分割し、各レイヤーで4つの対応する要素を同時に回転させます。
2. レイヤー構造の理解
4×4行列のレイヤー構造
レイヤー0(外側):
5
1
9
11
2
4
8
10
13
3
6
7
15
14
12
16
レイヤー1(内側):
5
1
9
11
2
4
8
10
13
3
6
7
15
14
12
16
3. 4要素同時回転の仕組み
回転パターンの説明
各レイヤーで、4つの対応する要素を以下の順序で回転させます:
4. アルゴリズムの詳細解析
レイヤー数の計算
// レイヤー数 = Math.floor(n / 2) // 3×3行列 → Math.floor(3/2) = 1レイヤー //
4×4行列 → Math.floor(4/2) = 2レイヤー // 5×5行列 → Math.floor(5/2) = 2レイヤー
for (let layer = 0; layer < Math.floor(n / 2); layer++)
なぜMath.floor(n/2)?
• 奇数サイズ: 中央要素は回転不要
• 偶数サイズ: 全要素が回転対象
• 外側から内側へ順次処理
各レイヤーの境界計算
const first = layer; // レイヤーの開始インデックス const last = n - 1 - layer;
// レイヤーの終了インデックス // 例: 4×4行列のレイヤー0の場合 // first = 0, last
= 4-1-0 = 3 // 処理範囲: [0,0] から [3,3] の外周
4要素の座標計算式
for (let i = first; i < last; i++) { const offset=i - first; //
現在位置からの相対位置 // 4つの対応する要素の座標 const topPos=[first, i]; //
上辺の要素 const rightPos=[i, last]; // 右辺の要素 const bottomPos=[last,
last-offset]; // 下辺の要素 const leftPos=[last-offset, first]; // 左辺の要素 }
座標の対応関係:
[0,0]
TOP
[0,1]
TOP
[0,2]
TOP
[0,3]
RIGHT
[1,0]
LEFT
4
8
[1,3]
RIGHT
[2,0]
LEFT
3
6
[2,3]
RIGHT
[3,0]
BOTTOM
[3,1]
BOTTOM
[3,2]
BOTTOM
[3,3]
BOTTOM
回転処理の実行順序
// 1. トップ要素を一時保存 const top = matrix[first][i]; // 2.
時計回りに4つの要素を移動 matrix[first][i] = matrix[last-offset][first]; // left
→ top matrix[last-offset][first] = matrix[last][last-offset]; // bottom → left
matrix[last][last-offset] = matrix[i][last]; // right → bottom matrix[i][last] =
top; // top → right (保存値を使用)
なぜこの順序?
• 最初にtop要素を保存しないと上書きされて失われる
• left→top→right→bottom→leftの循環で4要素を同時移動
• 一時変数は1つだけで済む(メモリ効率的)
完全なコード(コメント付き)
function rotate(matrix: number[][]): void { const n = matrix.length; //
外側から内側へレイヤーごとに処理 for (let layer = 0; layer < Math.floor(n / 2);
layer++) { const first=layer; // 現在レイヤーの開始位置 const last=n - 1 -
layer; // 現在レイヤーの終了位置 //
レイヤーの上辺を左から右へ処理(最後の要素は除く) for (let i=first; i < last;
i++) { const offset=i - first; // 現在処理中の4要素の座標 // top:
matrix[first][i] 例: [0][1] // right: matrix[i][last] 例: [1][3] // bottom:
matrix[last][last-offset] 例: [3][2] // left: matrix[last-offset][first] 例:
[2][0] const top=matrix[first][i]; // 上要素を退避 //
時計回りに回転(left→top→right→bottom→left) matrix[first][i]=matrix[last -
offset][first]; // left → top matrix[last - offset][first]=matrix[last][last -
offset]; // bottom → left matrix[last][last - offset]=matrix[i][last]; // right
→ bottom matrix[i][last]=top; // top → right } } }
5. 座標計算の詳細
4×4行列での座標例(レイヤー0、i=0の場合)
回転前の4要素:
[0,0]
5
1
9
11
2
4
8
[0,3]
10
13
3
6
7
[3,0]
15
14
12
[3,3]
16
座標計算:
layer=0, i=0, offset=0
top: [0][0] = 5
right: [0][3] = 10
bottom: [3][3] = 16
left: [3][0] = 15
→
回転後の4要素:
[0,0]
15
1
9
11
2
4
8
[0,3]
5
13
3
6
7
[3,0]
16
14
12
[3,3]
10
移動:
15 → [0,0] (left→top)
16 → [3,0] (bottom→left)
10 → [3,3] (right→bottom)
5 → [0,3] (top→right)
6. 完全なデモンストレーション
7. 計算量分析
時間計算量: O(n²)
• 各要素を正確に1回だけ処理
• ネストしたループだが、内部処理は定数時間
• 最適な時間計算量(全要素を移動する必要があるため)
空間計算量: O(1)
• 一時変数のみ使用(top変数のみ)
• 追加の配列やデータ構造は不要
• in-place操作を実現
8. アルゴリズムの利点
- メモリ効率: 追加のメモリを使用せずin-place操作
- 最適な時間計算量: 各要素を1回のみ処理
- 直感的: レイヤーごとの処理で理解しやすい
- スケーラブル: 任意のサイズのn×n行列に対応