coding test

[파이썬, Java] 16926. 배열 돌리기 1

잔망루피 2021. 11. 15. 21:41

문제

크기가 N×M인 배열이 있을 때, 배열을 돌려보려고 한다. 배열은 다음과 같이 반시계 방향으로 돌려야 한다.

A[1][1] ← A[1][2] ← A[1][3] ← A[1][4] ← A[1][5]
   ↓                                       ↑
A[2][1]   A[2][2] ← A[2][3] ← A[2][4]   A[2][5]
   ↓         ↓                   ↑         ↑
A[3][1]   A[3][2] → A[3][3] → A[3][4]   A[3][5]
   ↓                                       ↑
A[4][1] → A[4][2] → A[4][3] → A[4][4] → A[4][5]

예를 들어, 아래와 같은 배열을 2번 회전시키면 다음과 같이 변하게 된다.

1 2 3 4       2 3 4 8       3 4 8 6
5 6 7 8       1 7 7 6       2 7 8 2
9 8 7 6   →   5 6 8 2   →   1 7 6 3
5 4 3 2       9 5 4 3       5 9 5 4
 <시작>         <회전1>        <회전2>

배열과 정수 R이 주어졌을 때, 배열을 R번 회전시킨 결과를 구해보자.

입력

첫째 줄에 배열의 크기 N, M과 수행해야 하는 회전의 수 R이 주어진다.

둘째 줄부터 N개의 줄에 배열 A의 원소 Aij가 주어진다.

출력

입력으로 주어진 배열을 R번 회전시킨 결과를 출력한다.

제한

  • 2 ≤ N, M ≤ 300
  • 1 ≤ R ≤ 1,000
  • min(N, M) mod 2 = 0
  • 1 ≤ Aij ≤ 108

 

예제 입력 1 

4 4 2
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16

예제 출력 1 

3 4 8 12
2 11 10 16
1 7 6 15
5 9 13 14

 

예제 입력 2 

5 4 7
1 2 3 4
7 8 9 10
13 14 15 16
19 20 21 22
25 26 27 28

예제 출력 2 

28 27 26 25
22 9 15 19
16 8 21 13
10 14 20 7
4 3 2 1

 

예제 입력 3 

2 2 3
1 1
1 1

예제 출력 3 

1 1
1 1

 

 

🎨 나의 풀이

import java.io.*;
import java.util.*;

class Main{
    static int N, M, R;     // 배열의 크기, 회전 수
    static int[][] A;

    public static void main(String[] args) throws Exception{
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));

        StringTokenizer st=new StringTokenizer(br.readLine());
        N=Integer.parseInt(st.nextToken());
        M=Integer.parseInt(st.nextToken());
        R=Integer.parseInt(st.nextToken());

        A=new int[N][M];
        for(int n=0; n<N; n++){
            st=new StringTokenizer(br.readLine());
            for(int m=0; m<M; m++){
                A[n][m]=Integer.parseInt(st.nextToken());
            }
        }

        int prev=0;
        int tmp=0;
        int x=0;
        int y=0;

        for(int r=0; r<R; r++){     // 회전 수
            for(int i=0; i<Math.min(N, M)/2; i++){      // 몇 개를 회전시키는지(ㅁ가 몇개?)
                x=i;
                y=i;
                tmp=A[x][y];

                for(int j=i+1; j<N-i; j++){         // 아래
                    x=j;
                    prev=A[x][y];
                    A[x][y]=tmp;
                    tmp=prev;
                }

                for(int j=i+1; j<M-i; j++){         // 오른쪽
                    y=j;
                    prev=A[x][y];
                    A[x][y]=tmp;
                    tmp=prev;
                }

                for(int j=i+1; j<N-i; j++){         // 위
                    x=N-j-1;
                    prev=A[x][y];
                    A[x][y]=tmp;
                    tmp=prev;
                }

                for(int j=i+1; j<M-i; j++){         // 왼쪽
                    y=M-j-1;
                    prev=A[x][y];
                    A[x][y]=tmp;
                    tmp=prev;
                }
            }
        }

        for(int h=0; h<N; h++){
            for(int w=0; w<M; w++){
                System.out.print(A[h][w]+" ");
            }
            System.out.println();
        }

    }
}

다른 사람의 파이썬 풀이를 자바로 구현해봤다.

i는 ㅁ의 갯수다. 바깥에서 안쪽으로 들어갈수록 1개씩 늘어난다.

가장 바깥쪽은 i가 0, 그 다음은 1, 2, ..

prev에 현재 A[x][y]를 저장하고, A[x][y]=tmp를 한다.

tmp=prev를 하면 다음 인덱스에 이전 값이 저장된다.

 

 

# 실패
import sys
input=sys.stdin.readline

N, M, R=map(int, input().split())       # 배열의 크기, 회전의 수
A=[[0] for _ in range(N)]
answer=[[0]*M for _ in range(N)]

def solution(N, M, i) :
    for y in range(i, M - 1):
        answer[0][y] = A[0][y + 1]

    for x in range(i+1, N):
        answer[x][0] = A[x - 1][0]

    for y in range(i+1, M):
        answer[N - 1][y] = A[N - 1][y - 1]

    for x in range(N - 2-i, i-1, -1):
        answer[x][N - 1] = A[x + 1][N - 1]

for n in range(N):
    A[n] = list(map(int, input().split()))

for i in range(M//2) :
    solution(N-(i*2), M-(i*2), i)

print(answer)

안쪽은 값이 안 채워지네?!!

 

 

🦄 다른 사람 풀이

# https://resilient-923.tistory.com/303
import sys
input=sys.stdin.readline

n, m, r=map(int, input().split())

data=[list(map(int, input().split())) for _ in range(n)]

for _ in range(r) :
    for i in range(min(n, m) // 2) :
        # x, y는 돌려지는 배열중 가장 첫번째 배열 인덱스
        x, y=i, i
        temp=data[x][y]

        # 안쪽까지 계속 고려해야하기 때문에 n-i랑 m-i까지로 범위설정
        for j in range(i+1, n-i) :      # 하
            x=j
            prev_value=data[x][y]
            data[x][y]=temp
            temp=prev_value

        for j in range(i+1, m-i) :  # 우
            y=j
            prev_value=data[x][y]
            data[x][y]=temp
            temp=prev_value

        for j in range(i+1, n-i) :  # 상
            x=n-j-1
            prev_value=data[x][y]
            data[x][y]=temp
            temp=prev_value

        for j in range(i+1, m-i) :  # 좌
            y=m-j-1
            prev_value=data[x][y]
            data[x][y]=temp
            temp=prev_value

for i in range(n) :
    for j in range(m) :
        print(data[i][j], end=' ')
    print()

바깥쪽을 영역별로 색칠해보았다

for i in range(min(n, m)//2)는 가장자리부터 회전시킨 후 안쪽도 회전시킨다.

위의 표에서 색칠된 부분이 안쪽에도 반복된다.

prev_value에 저장한 값은 다음 인덱스 값에 들어간다.

 

 

# https://velog.io/@study-dev347/%EB%B0%B1%EC%A4%80-16926-%EB%B0%B0%EC%97%B4%EB%8F%8C%EB%A6%AC%EA%B8%B01
import sys
from collections import deque

n, m, r=map(int, sys.stdin.readline().rstrip().split())
arr=[list(map(int, sys.stdin.readline().rstrip().split())) for _ in range(n)]

def rotate(y, x, height, width) :
    global arr
    q=deque()

    for i in range(x, x+width) :
        q.append(arr[y][i])

    for i in range(y+1, y+height) :
        q.append(arr[i][x+width-1])

    for i in range(x+width-2, x, -1) :
        q.append(arr[y+height-1][i])

    for i in range(y+height-1, y, -1) :
        q.append(arr[i][x])

    q.rotate(-r)

    for i in range(x, x+width) :
        arr[y][i]=q.popleft()

    for i in range(y+1, y+height) :
        arr[i][x+width-1]=q.popleft()

    for i in range(x+width-2, x, -1) :
        arr[y+height-1][i]=q.popleft()

    for i in range(y+height-1, y, -1) :
        arr[i][x]=q.popleft()

height=n
width=m
y, x=0, 0

while True :
    if height == 0 or width == 0 : break

    rotate(y, x, height, width)
    y+=1
    x+=1
    height-=2
    width-=2

for i in range(n) :
    for j in range(m) :
        print(arr[i][j], end=' ')
    print()

deque에 순서대로 넣고 rotate로 반시계 방향 회전 시킨다.

rotate(n)에서 n이 음수면 반시계 방향 회전이다.

 

 

# https://handhand.tistory.com/185
import sys

def rotate() :
    x, y=0, 0
    n, m=N, M
    time=min(N, M)//2

    while time :
        cache=board[x][y]

        # 윗쪽
        for i in range(m-1) :
            board[x][y+i]=board[x][y+i+1]

        # 오른쪽
        for i in range(n-1) :
            board[x+i][y+m-1]=board[x+i+1][y+m-1]

        # 아래쪽
        for i in range(m-1) :
            board[x+n-1][y+m-1-i]=board[x+n-1][y+m-2-i]

        # 왼쪽
        for i in range(n-1) :
            board[x+n-1-i][y]=board[x+n-2-i][y]
        board[x+1][y]=cache

        n-=2
        m-=2
        x+=1
        y+=1
        time-=1

def solution() :
    for _ in range(R) :
        rotate()

    for row in board :
        print(*row)

if __name__ == '__main__' :
    N, M, R=list(map(int, sys.stdin.readline().split()))
    board=[list(map(int, sys.stdin.readline().split())) for _ in range(N)]

    solution()

이 풀이는 pypy3로 제출했을 때 통과한다.

while문을 한 번 돌때마다 n과 m이 2씩 줄어든다.

x, y는 시작점이다.

 

 

import java.io.*;
import java.util.*;

class Main{
    public static void main(String[] args) throws Exception{
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sb=new StringBuilder();
        StringTokenizer st=new StringTokenizer(br.readLine().trim());
        int N=Integer.parseInt(st.nextToken());
        int M=Integer.parseInt(st.nextToken());
        int R=Integer.parseInt(st.nextToken());
        int[][] A=new int[N][M];
        for(int i=0; i<N; i++){
            st=new StringTokenizer(br.readLine().trim());
            for(int j=0; j<M; j++){
                A[i][j]=Integer.parseInt(st.nextToken());
            }
        }

        int[] rot=new int[2*(N+M)-4];
        for(int i=0, size=Math.min(N, M)/2, n, m, idx, length; i<size; i++){
            n=N-2*i;
            m=M-2*i;
            length=0;
            for(int j=0; j<m-1; j++){		// 오른쪽
                rot[length++]=A[i][i+j];
            }
            for(int j=0; j<n-1; j++){		// 아래
                rot[length++]=A[i+j][M-i-1];
            }
            for(int j=0; j<m-1; j++){		// 왼쪽
                rot[length++]=A[N-i-1][M-i-j-1];
            }
            for(int j=0; j<n-1; j++){		// 아래
                rot[length++]=A[N-i-j-1][i];
            }
            idx=R%length;
            for(int j=0; j<m-1; j++){
                A[i][i+j]=rot[idx++ % length];
            }
            for(int j=0; j<n-1; j++){
                A[i+j][M-i-1]=rot[idx++ % length];
            }
            for(int j=0; j<m-1; j++){
                A[N-i-1][M-i-j-1]=rot[idx++ % length];
            }
            for(int j=0; j<n-1; j++){
                A[N-i-j-1][i]=rot[idx++%length];
            }
        }
        for(int i=0; i<N; i++){
            for(int j=0; j<M; j++){
                sb.append(A[i][j]).append(' ');
            }
            sb.append('\n');
        }
        System.out.println(sb);
        br.close();
    }
}

rot 배열에 순서대로 넣고 A 배열에 % 연산자를 이용해 값을 넣는다.

rot 배열의 크기는 가장 큰 ㅁ만큼이다.

 

 

// https://yongku.tistory.com/entry/%EB%B0%B1%EC%A4%80-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%B0%B1%EC%A4%80-16926%EB%B2%88-%EB%B0%B0%EC%97%B4%EB%8F%8C%EB%A6%AC%EA%B8%B01-%EC%9E%90%EB%B0%94Java
import java.util.*;

class Main{
    private static int[] dx={0, 1, 0, -1};      // 우상좌하
    private static int[] dy={1, 0, -1, 0};      // 우상좌하
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int N=sc.nextInt();     // 배열 크기
        int M=sc.nextInt();     // 배열 크기
        int R=sc.nextInt();     // 회전 수

        int[][] arr=new int[N][M];      // 배열 선언

        // 배열 입력
        for(int i=0; i<N; i++){
            for(int j=0; j<M; j++){
                arr[i][j]=sc.nextInt();
            }
        }

        // 돌려야하는 그룹 개수
        // 2*2 행렬에서는 1개, 5*5에서는 2개, 4*5에서는 2개, 최소값을 2로 나누면 그룹 수
        // 이 규칙에서 항상 시작점은 x, y 값이 같은 값에서 시작
        int group_value=Math.min(N, M)/2;

        // 회전횟수
        for(int i=0; i<R; i++){
            // 그룹 갯수만큼 반복
            for(int j=0; j<group_value; j++){
                int x=j;
                int y=j;

                // 나중에 값을 넣기 위해 따로 저장
                int value=arr[x][y];

                int idx=0;      // 방향

                while(idx < 4){
                    int nx=x+dx[idx];
                    int ny=y+dy[idx];

                    // 범위 내에 있을 경우 돌려
                    if(nx >= j && ny >= j && nx < N-j && ny < M-j){
                        arr[x][y]=arr[nx][ny];
                        x=nx;
                        y=ny;
                    }
                    // 범위 벗어나면 방향 전환
                    else idx++;
                }
                arr[j+1][j]=value;
            }
        }

        // 출력
        for(int i=0; i<N; i++){
            for(int j=0; j<M; j++){
                System.out.print(arr[i][j]+" ");
            }
            System.out.println();
        }
    }
}

개인적으로 이 풀이가 이해하기 쉽고 간결해서 좋다 👍

우상좌하 순으로 돈다.

범위를 벗어나면 idx를 1증가시켜 방향을 바꾼다.

한 번 순환하고 나면 시작점 값 value를 arr[j+1][j]에 넣어준다.

 

 

// https://wiselog.tistory.com/119
import java.io.*;
import java.util.*;

public class Main{
    public static void main(String[] args) throws IOException{
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st=new StringTokenizer(br.readLine());
        int h=Integer.parseInt(st.nextToken());
        int w=Integer.parseInt(st.nextToken());
        int n=Integer.parseInt(st.nextToken());         // 회전 횟수

        int[][] arr=new int[h][w];
        for(int i=0; i<h; i++){
            st=new StringTokenizer(br.readLine());
            for(int j=0; j<w; j++){
                arr[i][j]=Integer.parseInt(st.nextToken());
            }
        }

        int count=Math.min(h, w)/2;     // 돌아가는 라인의 수
        for(int i=0; i<n; i++){         // 회전 횟수만큼 반복
            for(int j=0; j<count; j++){     // 라인들 전부 돌리기
                int temp=arr[j][j];     // 맨 마지막에 넣기 위해 따로 저장
                for(int k=j+1; k<w-j; k++)
                    arr[j][k-1]=arr[j][k];

                for(int k=j+1; k<h-j; k++)
                    arr[k-1][w-1-j]=arr[k][w-1-j];

                for(int k=w-2-j; k>=j; k--)
                    arr[h-1-j][k+1]=arr[h-1-j][k];

                for(int k=h-2-j; k>=j; k--)
                    arr[k+1][j]=arr[k][j];

                arr[j+1][j]=temp;
            }
        }

        for(int j=0; j<h; j++){
            for(int k=0; k<w; k++){
                System.out.print(arr[j][k]+" ");
            }
            System.out.println();
        }
    }
}

위의 풀이처럼 시작값을 나중에 넣어준다.

다른 점은 for문으로 4방향을 돌린다.

위쪽, 오른쪽, 아래쪽, 왼쪽 순서로 진행된다.

 

 

문제 출처 👉 백준

반응형

'coding test' 카테고리의 다른 글

[파이썬] 9663. N-Queen  (0) 2022.11.10
[파이썬] 13460. 구슬 탈출 2  (0) 2021.12.08
[파이썬, Java] 2458. 키 순서  (0) 2021.11.01
[파이썬, Java] 1981. 배열에서 이동  (0) 2021.10.28
[파이썬, Java] 징검다리 건너기  (0) 2021.10.28