본문 바로가기
PS 문제 풀이/HackerRank

[HackerRank] Matrix Layer Rotation

by 까망 하르방 2021. 2. 18.
반응형

출처: https://www.hackerrank.com/challenges/matrix-rotation-algo/problem

 Input 

4 4 2

1 2 3 4

5 6 7 8

9 10 11 12

13 14 15 16

  

 Output 

3 4 8 12

2 11 10 16

1 7 6 15

5 9 13 14

Cycle의 개수는 m, n 중 작은 수의 2로 나누었을 때의 몫이다. 

ex) min (2 * 6)  2 / 2 = 1 

    min (8 * 9)  8 / 2 = 4

위와 같이 m, n 중 큰 수가 어떤 수든 상관없이 min( m, n ) / 2』로 계산해서

cycle 개수를 도출할 수 있다.

 

실제 이차원 배열상에서 rotation을 시킬 수도 있지만

 을 한 개의 『ㅡ』로 생각하여 rotation 처리

Circle Queue를 이용해서 제일 마지막 원소를 앞으로 삽입시켜주는 방식으로 구현

 

조건 중 1 ≤ r ≤ 10^9

는 상당히 큰 숫자이므로 모든 테두리를 주먹구구 방식으로 rotation을 할 수는 없다.

(8 * 9 Matrix)

* 여러 cycle이 존재한다면 각 cycle의 시작지점은 (0,0), (1,1), (2,2)....

(1) (8 + 9) * 2 - 4 = 30번 회전에 한 바퀴 주기  

(2) (6 + 7) * 2 - 4 = 22번 

(3) (4 + 5) * 2 - 4 = 14번 

(4) (2 + 3) * 2 - 4 = 6번 

(* 각 테두리를 『ㅡ』의 형태인 리스트에 보관했다면 리스트의 길이가 회전주기라고 볼 수 있다.)

 

r를 최소화하는 것에 대한 핵심은 다음과 같다.

실제 모든 cycle이 동시다발적으로 회전하지만 각 cycle마다 회전주기는 다르므로

최종 형태를 도출할 때는 각 cycle의 회전주기를 이용하여 최소한 회전시키는 것이다.

 

ex) 위의  (8 * 9 Matrix) 100번 회전 후의 형태는

- 100 % 30 = 10번만 회전

- 100 % 22 = 12번만 회전

- 100 % 14 = 2번만 회전

- 100 % 6 = 4번만 회전

이 경우, 처음 100 * 4번 수행하는 것보다 (10 + 12 + 2 + 4)번만큼만 수행한 것과 같다.

 

구현 순서는 다음과 같다.

1. 이차원 배열에서 cycle 개수 도출

2. 각 cycle을 리스트형태로 변형

3. 각 cycle마다 회전 횟수 재조정 후 회전

4. 회전 완료된 리스트를 이차원 배열형태로 변형


import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
 
public class Solution {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
 
        int m = Integer.parseInt(sc.next());
        int n = Integer.parseInt(sc.next());
        int r = Integer.parseInt(sc.next());
         
        int[][] arr = new int[m][n];
        for(int x=0; x<m; x++) {
            for(int y=0; y<n; y++) {
                arr[x][y] = Integer.parseInt(sc.next());
            }
        }
        // 1. 주어진 배열이 몇개의 cycle로 구성할 수 있는지 확인
        int cycle = Math.min(m, n) / 2;
                   
        // 리스트가 여러개 필요하므로 이를 동적으로 제어하기 위해
        // 리스트 안에 리스트를 넣어둠
        List<ArrayList<Integer>> cycleList = new ArrayList<ArrayList<Integer>>();
        for(int c=0; c<cycle; c++) {
            ArrayList<Integer> temp = new ArrayList<>();
            cycleList.add(temp);
        }
         
        // 2. 각 cycle(테두리)을 각각의 리스트에 보관하여 한 줄로 표시
        // cycle 방향으로 집어 넣을 수 있도록(하우상좌)
        int[] dx = {1, 0, -1, 0};
        int[] dy = {0, 1, 0, -1};
         
        for(int c=0; c<cycle; c++) {
            // 바깥쪽 테두리(cycle)부터 보관 (반시계 방향 탐색)
            ArrayList<Integer> temp = cycleList.get(c);
            // 각 cycle(테두리)의 시작 지점
            int x = c;
            int y = c;
             
            // 시작 지점을 리스트에 먼저 넣어둔다.
            // (시작지점은 -1로 표시안해도 탐색에 지장x)
            temp.add(arr[x][y]);
             
            // 탐색하면서 리스트에 값 저장
            for(int d=0; d<dx.length; d++) {
                // 특정 방향의 끝지점 까지
                while(true) {
                    x = x + dx[d];
                    y = y + dy[d];
                    if(x < 0 || y < 0 || x >= m  || y >= n) {
                        // 이어서 탐색하기 위해 배열 벗어난 index 재조정
                        x = x - dx[d];
                        y = y - dy[d];
                        break;
                    }
                    // 한바퀴 돌면서 시작 지점에 돌아왔으면 stop
                    // (for문이 다 수행된 순간)
                    if(x == c && y == c) {
                        break;
                    }
                     
                    // 제일 바깥쪽 테두리는 상관 없지만.
                    // 안쪽 테두리들은 바깥쪽 테두리를 침범하지 않으면서 탐색해야 한다.
                    // 즉 범위를 좁혀가야 하므로 탐색 표시를 음수(-1)로 표시
                    if(arr[x][y] == -1) {
                        // 이어서 탐색하기 위해 배열 벗어난 index 재조정
                        x = x - dx[d];
                        y = y - dy[d];
                        break;
                    }
                    // 해당 값 저장
                    temp.add(arr[x][y]);
                    // 탐색 표시
                    arr[x][y] = -1;
                }
            }
        }
                 
        // 3. r이 클 수 있기 때문에 각 테두리별로 회전 주기를 분석하여 맞춰준다.
        for(int i=0; i<cycleList.size(); i++) {
            ArrayList<Integer> temp = cycleList.get(i);
            // 해당 테두리 회전주기를 분석
            int rotation = r % temp.size();
            // 각 cycle(테두리) 회전 시작
            while(rotation-- > 0) {
                // 제일 뒤의 원소를 앞쪽으로 배치
                temp.add(0, temp.remove(temp.size()-1));    
            }    
        }
         
        // 4. 회전이 끝난 후 배열에 맞에 다시 재배치
        for(int c=0; c<cycle; c++) {
            // 바깥쪽 테두리(cycle)부터 재배치
            ArrayList<Integer> temp = cycleList.get(c);
            // 각 cycle(테두리)의 시작 지점
            int x = c;
            int y = c;
             
            // 시작 지점에 리스트의 제일 앞 원소부터 집어 넣는다.
            arr[x][y] = temp.remove(0);
             
            // 달팽이 모양으로 탐색
            for(int d=0; d<dx.length; d++) {
                // 특정 방향의 끝지점 까지
                while(true) {
                    x = x + dx[d];
                    y = y + dy[d];
                    if(x < 0 || y < 0 || x >= m  || y >= n) {
                        // 이어서 탐색하기 위해 배열 벗어난 index 재조정
                        x = x - dx[d];
                        y = y - dy[d];
                        break;
                    }
                    // 한바퀴 돌면서 시작 지점에 돌아왔으면 stop
                    // (for문이 다 수행된 순간)
                    if(x == c && y == c) {
                        break;
                    }
                     
                    // 제일 바깥쪽 테두리는 상관 없지만.
                    // 안쪽 테두리들은 바깥쪽 테두리를 침범하지 않으면서 탐색해야 한다.
                    // 역으로 음수 여부를 판단하면서 탐색
                    if(arr[x][y] != -1) {
                        // 이어서 탐색하기 위해 배열 벗어난 index 재조정
                        x = x - dx[d];
                        y = y - dy[d];
                        break;
                    }
                    arr[x][y] = temp.remove(0);
                }
            }
        }
         
        // 정답 출력
        for(int x=0; x<m; x++) {
            for(int y=0; y<n; y++) {
                System.out.print(arr[x][y] +" ");
            }
            System.out.println();
        }
    }
}

 

반응형

'PS 문제 풀이 > HackerRank' 카테고리의 다른 글

[HackerRank] Java Stack  (0) 2021.02.18
[HackerRank] Apple and Orange  (0) 2021.02.18
[HackerRank] Queen's Attack II  (2) 2021.02.18
[HackerRank] The Bomberman Game  (0) 2021.02.18
[HackerRank] Strange Counter  (0) 2021.02.18

댓글