문제 소개
다음과 같은 2차원 배열이 있다고 가정해 보겠습니다.
const arr = [
[1, 2, 3, 4],
[12,13,14,5],
[11,16,15,6],
[10,9, 8, 7]
];이 배열은 항상 정사각형 행렬(square matrix) 형태로 주어진다는 조건이 있습니다.
우리가 작성해야 할 자바스크립트 함수는 이 배열을 입력받아, 요소들을 바깥 테두리부터 시작해 나선형(spiral)으로 돌면서 안쪽 중심으로 수렴할 때까지 순서대로 모아 새로운 배열을 만드는 것입니다. 마치 달팽이가 행렬의 바깥쪽을 따라 안으로 기어 들어가며 흔적(snail trail)을 남기는 모습과 같습니다.
따라서 위 배열에 대한 출력 결과는 다음과 같아야 합니다.
const output = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
이 문제는 반복문 없이 재귀(recursion)만으로도 매우 간결하게 해결할 수 있습니다.
재귀 접근 방식
핵심 아이디어는 다음과 같습니다.
- 행렬의 첫 번째 행(맨 윗줄)을 잘라내어 결과 배열에 연결합니다.
- 남은 행렬을 시계 방향으로 90도 회전시킵니다. 각 열을 추출한 뒤 순서를 뒤집으면 회전과 같은 효과를 얻을 수 있습니다.
- 회전된 행렬에 대해 같은 과정을 재귀적으로 반복합니다.
- 행렬의 길이가 1 이하가 되면 남은 요소를 그대로 반환하고 재귀를 종료합니다.
예제 코드
다음은 전체 구현 코드입니다.
const arr = [
[1, 2, 3, 4],
[12,13,14,5],
[11,16,15,6],
[10,9, 8, 7]
];
const spiralForm = arr => {
return arr.length > 1 ?
arr.splice(0,1)[0]
.concat(spiralForm(arr[0].map((c, i) => {
return arr.map(r => r[i]);
})
.reverse())) :
arr[0]
}
console.log(spiralForm(arr));출력 결과
이 코드를 실행하면 콘솔에 다음과 같은 결과가 출력됩니다.
[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 ]
코드 동작 원리
spiralForm 함수는 먼저 arr.splice(0, 1)[0]로 맨 윗줄을 제거하면서 반환합니다. 이어서 arr[0].map((c, i) => arr.map(r => r[i])) 부분이 열 단위로 요소를 모아 남은 행렬을 회전시키고, .reverse()가 순서를 뒤집어 나선 방향의 순서를 완성합니다. 이렇게 변환된 행렬에 대해 스스로를 다시 호출(재귀)하며, 모든 요소가 하나의 배열로 모일 때까지 과정을 반복합니다. 마지막에는 행렬의 길이가 1이 되었을 때 남은 마지막 줄을 반환하며 재귀가 자연스럽게 종료됩니다.