行列の特殊な走査と変換アルゴリズム

ジグザグ行列印刷

行列をジグザグ状に印刷するアルゴリズムを実装します。このアルゴリズムでは、2つのポイントを使用して行列を対角線方向に走査します。

以下の変数を定義します:

  • int topLeftRow = 0 - 左上ポイントの行インデックス
  • int topLeftCol = 0 - 左上ポイントの列インデックス
  • int bottomRightRow = 0 - 右下ポイントの行インデックス
  • int bottomRightCol = 0 - 右下ポイントの列インデックス
  • int maxRow = matrix.length - 1 - 最終行インデックス
  • int maxCol = matrix[0].length - 1 - 最終列インデックス
  • boolean isUpward = false - 上向きに印刷するかどうかのフラグ

左上ポイントは右方向へ移動し、右端に達したら下方向へ移動します:

topLeftRow = (topLeftCol == maxCol) ? topLeftRow + 1 : topLeftRow;
topLeftCol = (topLeftCol == maxCol) ? topLeftCol : topLeftCol + 1;

右下ポイントは下方向へ移動し、下端に達したら右方向へ移動します:

bottomRightCol = (bottomRightRow == maxRow) ? bottomRightCol + 1 : bottomRightCol;
bottomRightRow = (bottomRightRow == maxRow) ? bottomRightRow : bottomRightRow + 1;

実際の印刷処理は別メソッドに委譲し、方向を交互に切り替えます:

public void printZigzagMatrix(int[][] matrix) {
    int topLeftRow = 0;
    int topLeftCol = 0;
    int bottomRightRow = 0;
    int bottomRightCol = 0;
    int maxRow = matrix.length - 1;
    int maxCol = matrix[0].length - 1;
    boolean isUpward = false;
    
    while (topLeftCol != maxCol + 1) {
        printDiagonal(matrix, topLeftRow, topLeftCol, bottomRightRow, bottomRightCol, isUpward);
        topLeftRow = (topLeftCol == maxCol) ? topLeftRow + 1 : topLeftRow;
        topLeftCol = (topLeftCol == maxCol) ? topLeftCol : topLeftCol + 1;
        bottomRightCol = (bottomRightRow == maxRow) ? bottomRightCol + 1 : bottomRightCol;
        bottomRightRow = (bottomRightRow == maxRow) ? bottomRightRow : bottomRightRow + 1;
        isUpward = !isUpward;
    }
}

public void printDiagonal(int[][] matrix, int row1, int col1, int row2, int col2, boolean isUpward) {
    if (isUpward) {
        while (row1 != row2 + 1) {
            System.out.print(matrix[row1++][col1--] + " ");
        }
    } else {
        while (row2 != row1 - 1) {
            System.out.print(matrix[row2--][col2++] + " ");
        }
    }
}

螺旋行列印刷 / LeetCode 54. 螺旋行列

行列を螺旋状に印刷するアルゴリズムを実装します。外側から内側へ向かって螺旋状に要素を印刷していきます。

各層の四隅の座標を追跡します:

  • 左上: [startRow][startCol]
  • 右上: [startRow][endCol]
  • 右下: [endRow][endCol]
  • 左下: [endRow][startCol]

印刷処理は以下のステップで行います:

  1. 左上から右上へ(右方向)
  2. 右上から右下へ(下方向)
  3. 右下から左下へ(左方向)
  4. 左下から左上へ(上方向)

各層の印刷が完了したら、境界を内側に移動します:

public void printSpiralMatrix(int[][] matrix) {
    if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
        return;
    }
    
    int startRow = 0;
    int startCol = 0;
    int endRow = matrix.length - 1;
    int endCol = matrix[0].length - 1;
    
    while (startRow <= endRow && startCol <= endCol) {
        // 上辺を左から右へ
        for (int i = startCol; i <= endCol; i++) {
            System.out.print(matrix[startRow][i] + " ");
        }
        startRow++;
        
        // 右辺を上から下へ
        for (int i = startRow; i <= endRow; i++) {
            System.out.print(matrix[i][endCol] + " ");
        }
        endCol--;
        
        // 下辺を右から左へ(行が残っている場合)
        if (startRow <= endRow) {
            for (int i = endCol; i >= startCol; i--) {
                System.out.print(matrix[endRow][i] + " ");
            }
            endRow--;
        }
        
        // 左辺を下から上へ(列が残っている場合)
        if (startCol <= endCol) {
            for (int i = endRow; i >= startRow; i--) {
                System.out.print(matrix[i][startCol] + " ");
            }
            startCol++;
        }
    }
}

正方行列の回転

正方行列を90度時計回りに回転させるアルゴリズムを実装します。このアルゴリズムは、行列を外側から内側へ層ごとに処理していきます。

各層の四隅の座標を追跡します:

  • 左上: [top][left]
  • 右上: [top][right]
  • 右下: [bottom][right]
  • 左下: [bottom][left]

各層内の要素をグループ化し、各グループ内で要素を回転させます:

public void rotateSquareMatrix(int[][] matrix) {
    if (matrix == null || matrix.length == 0 || matrix.length != matrix[0].length) {
        return;
    }
    
    int top = 0;
    int left = 0;
    int bottom = matrix.length - 1;
    int right = matrix[0].length - 1;
    
    while (top < bottom) {
        rotateLayer(matrix, top, left, bottom, right);
        top++;
        left++;
        bottom--;
        right--;
    }
}

public void rotateLayer(int[][] matrix, int top, int left, int bottom, int right) {
    for (int offset = 0; offset < right - left; offset++) {
        // 左上の要素を保存
        int temp = matrix[top][left + offset];
        
        // 左下 → 左上
        matrix[top][left + offset] = matrix[bottom - offset][left];
        
        // 右下 → 左下
        matrix[bottom - offset][left] = matrix[bottom][right - offset];
        
        // 右上 → 右下
        matrix[bottom][right - offset] = matrix[top + offset][right];
        
        // 一時保存 → 右上
        matrix[top + offset][right] = temp;
    }
}

このアルゴリズムの時間計算量はO(N²)で、Nは行列のサイズです。空間計算量はO(1)であり、追加のメモリを使用せずにインプレースで回転を行います。

タグ: 行列 アルゴリズム ジグザグ走査 螺旋行列 行列回転

6月12日 22:48 投稿