BOJ[20327] - 배열 돌리기 6 by JavaScript
배열 돌리기 6
문제
언어
- JavaScript
순서도
- 1 ~ 8 번 연산에 대한 함수 구현
- 입력으로 주어진 배열에 R개의 연산을 순서대로 수행
- 결과 배열을 문자열 형태로 출력
문제 풀이 step 1
- 본 문제는 시뮬레이션 형식의 문제로, 문제에서 주어진 조건대로 로직을 짜는 문제입니다.
- 1번 연산은 각 부분 배열에 대해서 상하 반전시키면 됩니다.
- 2번 연산은 각 부분 배열에 대해서 좌우 반전시키면 됩니다.
- 5번 연산은 부분 배열을 한 칸으로 생각하고 상하 반전시키면 됩니다.
- 6번 연산은 부분 배열을 한 칸으로 생각하고 좌우 반전시키면 됩니다.
- 조금 어려웠던 부분은 3번 연산과 7번 연산입니다.
- 4번 연산과 8번 연산은 3번 연산과 7번 연산에서 대입하는 배열과 대입되는 배열을 서로 바꾸기만 하면 됩니다.
- 따라서 3번 연산과 7번 연산에 대해서 중점적으로 알아보겠습니다.
문제 풀이 step 2
- 3번 연산은 각 부분 배열을 오른쪽으로 90도 회전시켜야 합니다.
- 차근히 배열의 인덱스의 변화를 살펴보겠습니다.
- before 배열을 오른쪽으로 90도 회전시키면 after 배열처럼 index 가 변하게 됩니다.
- before 배열과 after 배열의 각 요소의 index 의 차이를 나타낸 것이 diff 배열입니다.
- 편하게 보기 위해서 배열의 요소를 문자열로 표현하게 되었습니다.
// 부분 배열의 크기가 4 인 경우
const before = [
"[0, 0], [0, 1], [0, 2], [0, 3]",
"[1, 0], [1, 1], [1, 2], [1, 3]",
"[2, 0], [2, 1], [2, 2], [2, 3]",
"[3, 0], [3, 1], [3, 2], [3, 3]",
];
const after = [
"[3, 0], [2, 0], [1, 0], [0, 0]",
"[3, 1], [2, 1], [1, 1], [0, 1]",
"[3, 2], [2, 2], [1, 2], [0, 2]",
"[3, 3], [2, 3], [1, 3], [0, 3]",
];
const diff = [
"[3, 0], [2, -1], [1, -2], [0, -3]",
"[2, 1], [1, 0], [0, -1], [-1, -2]",
"[1, 2], [0, 1], [-1, 0], [-2, -1]",
"[0, 3], [-1, 2], [-2, 1], [-3, 0]",
];
const element = ["[x, y]"];
- diff 배열을 보면서 우리는 규칙을 찾을 수 있습니다.
- 우선 x 좌표가 어떻게 변하는지 보겠습니다.
- x 좌표의 초기값은 “부분 배열의 크기 - 1” 입니다.
- 그리고 x 좌표는 오른쪽으로 갈수록 1 씩 감소합니다. 마찬가지로 아래로 내려갈수록 1 씩 감소합니다.
- 그 다음 y 좌표가 어떻게 변하는지 보겠습니다.
- y 좌표의 초기값은 “0” 입니다.
- 그리고 y 좌표는 오른쪽으로 갈수록 1 씩 감소합니다. 반면에 아래로 내려갈수록 1 씩 증가합니다.
- 이렇게 알아본 x 좌표와 y 좌표의 변화를 코드로 표현하면 아래와 같습니다.
// step 은 부분 배열의 크기를 의미
for (let x = i; x < i + step; x++) {
let xDiff = step - 1 - (x - i); // x 좌표의 변화량을 의미
let yDiff = 0 + (x - i); // y 좌표의 변화량을 의미
for (let y = j; y < j + step; y++) {
res[x][y] = arr[x + xDiff--][y + yDiff--];
}
}
- 3 번 연산은 이렇게 구현할 수 있고, 4 번 연산은 두 번째 for 문 안에 있는 res 와 arr 배열의 index 를 서로 봐꿔주기만 하면 됩니다.
res[x + xDiff--][y + yDiff--] = arr[x][y];
문제 풀이 step 3
- 7번 연산은 부분 배열을 한 칸으로 생각하고 오른쪽으로 90도 회전시켜야 합니다.
- 차근히 배열의 인덱스의 변화를 살펴보겠습니다.
- before 배열의 각 부분 배열을 한 칸으로 생각하고, 오른쪽으로 90도 회전시키면 after 배열처럼 index 가 변하게 됩니다.
- before 배열과 after 배열의 각 요소의 index 의 차이를 나타낸 것이 diff 배열입니다.
- 편하게 보기 위해서 배열의 요소를 문자열로 표현하게 되었습니다.
// 부분 배열의 크기가 2 인 경우
const before = [
"[[0, 0], [0, 1]], [[0, 2], [0, 3]], [[0, 4], [0, 5]], [[0, 6], [0, 7]]",
"[[1, 0], [1, 1]], [[1, 2], [1, 3]], [[1, 4], [1, 5]], [[1, 6], [1, 7]]",
"[[1, 0], [1, 1]], [[1, 2], [1, 3]], [[1, 4], [1, 5]], [[1, 6], [1, 7]]",
"[[1, 0], [1, 1]], [[1, 2], [1, 3]], [[1, 4], [1, 5]], [[1, 6], [1, 7]]",
"5 번째 행...",
"6 번째 행...",
"7 번째 행...",
"8 번째 행...",
];
const after = [
"[[6, 0], [6, 1]], [[4, 0], [4, 1]], [[2, 0], [2, 1]], [[0, 0], [0, 1]]",
"[[7, 0], [7, 1]], [[5, 0], [5, 1]], [[3, 0], [3, 1]], [[1, 0], [1, 1]]",
"[[6, 2], [6, 3]], [[4, 2], [4, 3]], [[2, 2], [2, 3]], [[0, 2], [0, 3]]",
"[[7, 2], [7, 3]], [[5, 2], [5, 3]], [[3, 2], [3, 3]], [[1, 2], [1, 3]]",
"5 번째 행...",
"6 번째 행...",
"7 번째 행...",
"8 번째 행...",
];
const diff = [
"[[6, 0], [6, 0]], [[4, -2], [4, -2]], [[2, -4], [2, -4]], [[0, -6], [0, -6]]",
"[[6, 0], [6, 0]], [[4, -2], [4, -2]], [[2, -4], [2, -4]], [[0, -6], [0, -6]]",
"[[4, 2], [4, 2]], [[2, 0], [2, 0]], [[0, -2], [0, -2]], [[-2, -4], [-2, -4]]",
"[[4, 2], [4, 2]], [[2, 0], [2, 0]], [[0, -2], [0, -2]], [[-2, -4], [-2, -4]]",
"5 번째 행...",
"6 번째 행...",
"7 번째 행...",
"8 번째 행...",
];
const element = ["[x, y]"];
- 이번에도 diff 배열을 보면서 우리는 규칙을 찾을 수 있습니다.
- 우선 x 좌표가 어떻게 변하는지 보겠습니다.
- 부분 배열을 한 칸으로 보기 때문에 부분 배열 내에서는 변화가 없습니다.
- x 좌표의 초기값은 “전체 배열의 크기 - 부분 배열의 크기” 입니다.
- 그리고 x 좌표는 오른쪽으로 갈수록 “부분 배열의 크기” 만큼씩 감소합니다. 마찬가지로 아래로 내려갈수록 “부분 배열의 크기”만큼씩 감소합니다.
- 그 다음 y 좌표가 어떻게 변하는지 보겠습니다.
- 마찬가지로 부분 배열을 한 칸으로 보기 때문에 부분 배열 내에서는 변화가 없습니다.
- y 좌표의 초기값은 “0” 입니다.
- 그리고 y 좌표는 오른쪽으로 갈수록 “부분 배열의 크기” 만큼씩 감소합니다. 반면에 아래로 내려갈수록 “부분 배열의 크기”만큼씩 증가합니다.
- 이렇게 알아본 x 좌표와 y 좌표의 변화를 코드로 표현하면 아래와 같습니다.
let xBase = len - step;
let yBase = 0;
for (let i = 0; i < len; i += step) {
let xDiff = xBase;
let yDiff = yBase;
// 부분 배열을 한 칸으로 생각하고 배열을 오른쪽으로 90도 회전
for (let j = 0; j < len; j += step) {
for (let x = i; x < i + step; x++) {
for (let y = j; y < j + step; y++) {
res[x][y] = arr[x + xDiff][y + yDiff];
}
}
xDiff -= step;
yDiff -= step;
}
xBase -= step;
yBase += step;
}
- 7 번 연산은 이렇게 구현할 수 있고, 8 번 연산은 두 번째 for 문 안에 있는 res 와 arr 배열의 index 를 서로 바꿔주기만 하면 됩니다.
res[x + Diff][y + diff] = arr[x][y];
문제풀이 step 4
- 주어지는 배열에 위에서 구현한 각 연산 함수를 적용시켜서 연산을 수행하고, 그 결과값을 출력하면 정답이 됩니다.
- 추가 설명은 주석으로 작성하겠습니다.
후기
- 꼭 다시 풀어볼 문제입니다.
- 본 문제를 푸는데 3시간 이상 사용했습니다. 너무 아쉽고 다음에 풀 때는 좀 더 빠르게 풀 수 있기를 기원합니다.
- 역시 이런 문제는 index 를 다 나열해 보면서 어떻게 변하는지 파악하는 것이 중요한 것 같습니다.
- 마치 아이큐 문제처럼 어떤 수의 나열을 보고 그 변화를 파악하는 문제와 유사한 것 같습니다.
소스 코드
const input = require("fs")
.readFileSync("/dev/stdin")
.toString()
.trim()
.split("\n");
const operators = {
1: (len, arr, l) => {
if (l === 0) return arr;
const res = Array.from({length: len}, () => []);
const step = Math.pow(2, l);
for (let i = 0; i < len; i += step) {
for (let j = 0; j < len; j += step) {
// 각 부분 배열을 상하 반전
for (let y = j; y < j + step; y++) {
for (let x = i; x < i + step; x++) {
res[x][y] = arr[i + step - 1 - (x - i)][y];
}
}
}
}
return res;
},
2: (len, arr, l) => {
if (l === 0) return arr;
const res = Array.from({length: len}, () => []);
const step = Math.pow(2, l);
for (let i = 0; i < len; i += step) {
for (let j = 0; j < len; j += step) {
// 각 부분 배열을 좌우 반전
for (let x = i; x < i + step; x++) {
for (let y = j; y < j + step; y++) {
res[x][y] = arr[x][j + step - 1 - (y - j)];
}
}
}
}
return res;
},
3: (len, arr, l) => {
if (l === 0) return arr;
const res = Array.from({length: len}, () => []);
const step = Math.pow(2, l);
for (let i = 0; i < len; i += step) {
for (let j = 0; j < len; j += step) {
// 각 부분 배열을 오른쪽으로 90도 회전
for (let x = i; x < i + step; x++) {
let xDiff = step - 1 - (x - i);
let yDiff = 0 + (x - i);
for (let y = j; y < j + step; y++) {
res[x][y] = arr[x + xDiff--][y + yDiff--];
}
}
}
}
return res;
},
4: (len, arr, l) => {
if (l === 0) return arr;
const res = Array.from({length: len}, () => []);
const step = Math.pow(2, l);
for (let i = 0; i < len; i += step) {
for (let j = 0; j < len; j += step) {
// 각 부분 배열을 왼쪽으로 90도 회전
// 3번 연산에서 res 의 index 와 arr 의 index 를 서로 바꿔주기
for (let x = i; x < i + step; x++) {
let xDiff = step - 1 - (x - i);
let yDiff = 0 + (x - i);
for (let y = j; y < j + step; y++) {
res[x + xDiff--][y + yDiff--] = arr[x][y];
}
}
}
}
return res;
},
5: (len, arr, l) => {
const res = Array.from({length: len}, () => []);
const step = Math.pow(2, l);
let xDiff = len - step;
for (let i = 0; i < len; i += step) {
for (let j = 0; j < len; j += step) {
// 부분 배열을 한 칸으로 생각하고 배열을 상하 반전
for (let x = i; x < i + step; x++) {
for (let y = j; y < j + step; y++) {
res[xDiff + (x - i)][y] = arr[x][y];
}
}
}
xDiff -= step;
}
return res;
},
6: (len, arr, l) => {
const res = Array.from({length: len}, () => []);
const step = Math.pow(2, l);
let yDiff = len - step;
for (let j = 0; j < len; j += step) {
for (let i = 0; i < len; i += step) {
// 부분 배열을 한 칸으로 생각하고 배열을 좌우 반전
for (let x = i; x < i + step; x++) {
for (let y = j; y < j + step; y++) {
res[x][yDiff + (y - j)] = arr[x][y];
}
}
}
yDiff -= step;
}
return res;
},
7: (len, arr, l) => {
const res = Array.from({length: len}, () => []);
const step = Math.pow(2, l);
let xBase = len - step;
let yBase = 0;
for (let i = 0; i < len; i += step) {
let xDiff = xBase;
let yDiff = yBase;
// 부분 배열을 한 칸으로 생각하고 배열을 오른쪽으로 90도 회전
for (let j = 0; j < len; j += step) {
for (let x = i; x < i + step; x++) {
for (let y = j; y < j + step; y++) {
res[x][y] = arr[x + xDiff][y + yDiff];
}
}
xDiff -= step;
yDiff -= step;
}
xBase -= step;
yBase += step;
}
return res;
},
8: (len, arr, l) => {
const res = Array.from({length: len}, () => []);
const step = Math.pow(2, l);
let xBase = len - step;
let yBase = 0;
for (let i = 0; i < len; i += step) {
let xDiff = xBase;
let yDiff = yBase;
// 부분 배열을 한 칸으로 생각하고 배열을 왼쪽으로 90도 회전
// 7번 연산에서 res 의 index 와 arr 의 index 를 서로 바꿔주기
for (let j = 0; j < len; j += step) {
for (let x = i; x < i + step; x++) {
for (let y = j; y < j + step; y++) {
res[x + xDiff][y + yDiff] = arr[x][y];
}
}
xDiff -= step;
yDiff -= step;
}
xBase -= step;
yBase += step;
}
return res;
},
};
const solution = (input) => {
const [n, r] = input[0].split(" ").map(Number);
const len = Math.pow(2, n);
let arr = input.slice(1, len + 1).map((v) => v.split(" ").map(Number));
for (let i = len + 1; i < len + 1 + r; i++) {
const [k, l] = input[i].split(" ").map(Number);
arr = operators[k](len, arr, l);
}
return arr.map((v) => v.join(" ")).join("\n");
};
console.log(solution(input));