문제
크기가 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 |