Coding test

[프로그래머스] 행렬 테두리 회전하기 (Lv 2) - javascript

Jiwoo 2022. 6. 29. 11:32

📝 문제

rows x columns 크기인 행렬이 있습니다. 행렬에는 1부터 rows x columns까지의 숫자가 한 줄씩 순서대로 적혀있습니다. 이 행렬에서 직사각형 모양의 범위를 여러 번 선택해, 테두리 부분에 있는 숫자들을 시계방향으로 회전시키려 합니다. 각 회전은 (x1, y1, x2, y2)인 정수 4개로 표현하며, 그 의미는 다음과 같습니다.

 

  • x1 행 y1 열부터 x2 행 y2 열까지의 영역에 해당하는 직사각형에서 테두리에 있는 숫자들을 한 칸씩 시계방향으로 회전합니다.

다음은 6 x 6 크기 행렬의 예시입니다.

 

문제 더보기

 

🔑 나의 풀이

function solution(rows, columns, queries) {
   
    let answer = [];
    let board = Array.from({length: rows+1}, () => new Array(columns+1)); 
    
    for(let i = 1; i <= rows; i ++) { 
        for(let j = 1; j <= columns; j++) {
            board[i][j] = ((i-1) * columns + j);
        }
    }
    
    queries.forEach(query => {
        
        let [fromR,fromC,toR,toC] = query;
        let r = fromR;
        let c = fromC;
        let cur = board[r][c]; 
        let next = 0;
        let min = rows * columns

        // 상단 (왼 -> 오)
        for(let i = fromC; i < toC; i++) {
            if(min > cur) min = cur;
             next = board[r][++c];
             board[r][c] = cur;
             cur = next;
        }

        // 우측 (위 -> 아래)
        for(let i = fromR; i < toR; i++) {
            if(min > cur) min = cur;
             next = board[r++][c];
             board[r][c] = cur;
             cur = next;
        }

        // 아래쪽 (오 -> 왼)
        for(let i = fromC; i < toC; i++) {
            if(min > cur) min = cur;
             next = board[r][--c];
             board[r][c] = cur;
             cur = next;
        }

        // 왼쪽 (아래 -> 위)
        for(let i = fromR; i < toR; i++) {
            if(min > cur) min = cur;
             next = board[--r][c];
             board[r][c] = cur;
             cur = next;
        }

        answer.push(min);
    })
    
    return answer;

}

 

풀이 설명

function solution(rows, columns, queries) {
   
    let answer = [];
    let board = Array.from({length: rows+1}, () => new Array(columns+1)); // 행렬의 틀 만들기
    
    for(let i = 1; i <= rows; i ++) { // 행렬 채우기
        for(let j = 1; j <= columns; j++) {
            board[i][j] = ((i-1) * columns + j);
        }
    }
    
    // queries의 요소 순회 // ex) [2,2,5,4]
    queries.forEach(query => {
        
        let [fromR,fromC,toR,toC] = query;
        let r = fromR; // 출발 위치
        let c = fromC;
        let cur = board[r][c]; // 옮길 값 저장
        let next = 0; // 다음으로 옮길 값 저장
        let min = rows * columns // 최소값 저장할 변수 

        // 상단 (왼 -> 오)
        for(let i = fromC; i < toC; i++) {
            if(min > cur) min = cur; // cur이 더 작으면 저장
             next = board[r][++c]; // 해당 값 next에 저장
             board[r][c] = cur; // 그 자리에 cur 넣기
             cur = next; // cur이 next값이 됨
        }

        // 우측 (위 -> 아래)
        for(let i = fromR; i < toR; i++) {
            if(min > cur) min = cur;
             next = board[++r][c];
             board[r][c] = cur;
             cur = next;
        }

        // 아래쪽 (오 -> 왼)
        for(let i = fromC; i < toC; i++) {
            if(min > cur) min = cur;
             next = board[r][--c];
             board[r][c] = cur;
             cur = next;
        }

        // 왼쪽 (아래 -> 위)
        for(let i = fromR; i < toR; i++) {
            if(min > cur) min = cur;
             next = board[--r][c];
             board[r][c] = cur;
             cur = next;
        }

        answer.push(min); // 순회를 마쳤으니 min은 회전한 수 중 최소값임
    })
    
    return answer;

}

 

초기 행렬을 만들지 않고 변경하는 값만 저장하려고 했는데 그게 더 복잡해져서 그냥 만들고 했다.

다른 풀이를 보니 큐를 이용해서 일단 값을 뺀 다음, 회전하고 다시 집어넣는 방법도 있던데,

난 그냥 회전하는 그대로 구현하고 그 과정에서 최소값이랑 비교해주는 방법을 택했다.

까다롭지는 않았으나 은근히 복잡했던 문제

 

주의할 점은 주어진 ((i-1) x columns + j) 식의 i행과 j열은 1부터 시작한다.

그러므로 행렬을 (rows + 1) x (columns + 1) 크기만큼 만들고 채워야 계산이 쉽다.

실제로는 rows x columns 만큼의 행렬만 채워지지만, 답을 구하는 데는 상관없다. 

 

초기 행렬을 만들고 -> 보기에 따라 회전해서 각 값에 저장 -> 회전하는 값 중 최소값 저장 -> answer 반환

 

  • 정확도 테스트 결과