N Log

2차원 배열 대각선 순환 이동

문제

배열을 입력받아 새 배열을 만들지 않고 원본 배열을 오른쪽 아래 대각선 방향으로 한 칸씩 순환 이동하는 함수를 작성하시오.
마지막 행은 첫 번째 행으로 이어지고, 마지막 열은 첫 번째 열로 이어진다.

input:
[
    [  1,  2,  3,  4,  5,  6 ],
    [ 11, 12, 13, 14, 15, 16 ],
    [ 21, 22, 23, 24, 25, 26 ],
    [ 31, 32, 33, 34, 35, 36 ],
    [ 41, 42, 43, 44, 45, 46 ]
]

output:
[
    [ 46, 41, 42, 43, 44, 45 ],
    [  6,  1,  2,  3,  4,  5 ],
    [ 16, 11, 12, 13, 14, 15 ],
    [ 26, 21, 22, 23, 24, 25 ],
    [ 36, 31, 32, 33, 34, 35 ]
]

풀이

class Main {
    public static void shiftDiagonally(int[][] matrix) {
        for (int row = 0; row < matrix.length; row++) {
            int lastColValue = matrix[row][matrix[row].length - 1];

            for (int col = matrix[row].length - 1; col > 0; col--) {
                matrix[row][col] = matrix[row][col - 1];
            }

            matrix[row][0] = lastColValue;
        }

        for (int col = 0; col < matrix[0].length; col++) {
            int lastRowValue = matrix[matrix.length - 1][col];

            for (int row = matrix.length - 1; row > 0; row--) {
                matrix[row][col] = matrix[row - 1][col];
            }

            matrix[0][col] = lastRowValue;
        }
    }

    public static void printMatrix(int[][] matrix) {
        for (int row = 0; row < matrix.length; row++) {
            for (int col = 0; col < matrix[row].length; col++) {
                System.out.printf("%3d", matrix[row][col]);
            }

            System.out.println();
        }
    }

    public static void main(String[] args) {
        int[][] matrix = {
            {  1,  2,  3,  4,  5,  6 },
            { 11, 12, 13, 14, 15, 16 },
            { 21, 22, 23, 24, 25, 26 },
            { 31, 32, 33, 34, 35, 36 },
            { 41, 42, 43, 44, 45, 46 }
        };

        System.out.println("input:");
        printMatrix(matrix);

        shiftDiagonally(matrix);

        System.out.println();
        System.out.println("output:");
        printMatrix(matrix);
    }
}

값 1개를 오른쪽 아래 대각선으로 이동하는 것은 쉽다.
현재 값을 행과 열을 1씩 증가시킨 위치에 대입하면 된다.
만약 증가시킨 행이나 열이 배열의 경계를 넘으면 나머지 연산자로 다시 배열 안의 위치로 보정하면 된다.

matrix[(row + 1) % rowCount][(col + 1) % colCount] = matrix[row][col];

다만 이대로 구현하면 문제점이 있다.
0행 0열에 있는 값 1을 1행 1열에 대입하면 원래 있던 값 12를 덮어쓰게 된다.
덮어쓰기 전의 값 12를 보관해 두었다가 나중에 2행 2열에 대입하면 이번에는 23을 덮어쓰게 된다.
대각선 이동 경로를 따라 값을 순환시키는 방식으로 구현하면 코드가 복잡해진다.
그래서 문제를 다시 생각해 보자.
대각선 이동은 행과 열이 각각 1씩 증가하는 이동인데, 이 과정을 2단계로 나누어 볼 수 있다.

각 행의 요소를 오른쪽으로 이동:
원본: [  1,  2,  3,  4,  5,  6 ]
        -------------------->
결과: [  6,  1,  2,  3,  4,  5 ]

행의 마지막 요소를 보관해 두고 모든 요소를 오른쪽으로 한 칸씩 민 다음, 첫 번째 인덱스에 보관해 둔 값을 대입하면 행 안에서 열 순환 이동을 구현할 수 있다.
각 행의 요소를 오른쪽으로 한 칸씩 순환 이동하면 다음과 같다.

[
    [  6,  1,  2,  3,  4,  5 ],
    [ 16, 11, 12, 13, 14, 15 ],
    [ 26, 21, 22, 23, 24, 25 ],
    [ 36, 31, 32, 33, 34, 35 ],
    [ 46, 41, 42, 43, 44, 45 ]
]

이제 각 열의 요소를 아래로 한 칸씩 순환 이동하면 최종 결과를 만들 수 있다.