문제 설명
양의 정수 n이 매개변수로 주어집니다. n × n 배열에 1부터 n2 까지 정수를 인덱스 [0][0]부터 시계방향 나선형으로 배치한 이차원 배열을 return 하는 solution 함수를 작성해 주세요.
✅ 코드
function solution(n) {
const result = Array.from(Array(n), () => Array(n).fill(0)); // n x n 배열 생성
let num = 1; // 시작 숫자
let row = 0; // 행의 시작 인덱스
let col = 0; // 열의 시작 인덱스
for (let i = n; i > 0; i -= 2) {
// 오른쪽으로 이동
for (let j = 0; j < i; j++) {
result[row][col] = num++;
col++;
}
col--;
row++;
// 아래로 이동
for (let j = 0; j < i - 1; j++) {
result[row][col] = num++;
row++;
}
row--;
col--;
// 왼쪽으로 이동
for (let j = 0; j < i - 1; j++) {
result[row][col] = num++;
col--;
}
col++;
row--;
// 위로 이동
for (let j = 0; j < i - 2; j++) {
result[row][col] = num++;
row--;
}
row++;
col++;
}
return result;
}
이 문제는 해결법이 떠오르지가 않아서🥲 많이 고생한 문제이다.
우선 n*n형태의 배열을 형성하는 법을 몰랐고, 한변의 길이를 이용해서 푼다는 생각을 못했다.
한변의 길이를 i로 설정하고 그 값을 for문을 통해서 조정하면서 반복하는것이 이 문제의 핵심이라고 생각했다.
코드를 순서대로 해석하면,
1️⃣ n x n 배열 생성 (초기값 0으로)
const result = Array.from(Array(n), () => Array(n).fill(0)); // n x n 배열 생성
Array.from()과 Array()를 이용해서 n*n의 배열을 생성한다.
그런다음, fill(0을 통해서 초기값을 0으로 설정한다.
2️⃣ num, row, col 선언, 값 할당
let num = 1; // 시작 숫자
let row = 0; // 행의 시작 인덱스
let col = 0; // 열의 시작 인덱스
실제값이 들어가는 것을 num으로 이름을 짓고 1을 처음값으로 넣어준다. (맨 처음에 들어갈 값이 1이므로)
각 배열의 위치를 이동시킬때 행과 열의 인덱스를 이용할 것이므로, 열의 인덱스의 이름은 row로 행의 인덱스의 이름은 col이라고 지어주었다. 그런다음 각각 0의 값을 넣었다. (인덱스의 시작이 [0,0]이므로)
3️⃣ 한변의 길이 i 를 이용해서 for문 만들기
for (let i = n; i > 0; i -= 2) {
...
}
for (let i = n; i > 0; i -= 2)은 배열을 나선형으로 순회하기 위한 반복문
이 구문에서 i는 현재 반복 단계에서 탐색할 숫자를 배치할 수 있는 한 변의 길이를 나타낸다.
배열이 나선형으로 돌면서 길이가 계속 변화되는데, 그때마다 길이가 2씩 줄어든다.
그림으로 나타내면 아래와 같이 나타낼 수 있다.
파란색이 처음의 한변의 길이이다. 이때 한변의 길이 i = n과 같다 (n=4로 설정했을때 예시)
한바퀴를 다 돌고 안쪽 나선으로 들어갈때 i의 길이는 2가 줄어든다. (안쪽 빨간색의 길이를 보면 된다)
이렇게 한바퀴를 반복할때마다 i의 길이가 2씩 줄어드므로 for문을 이용해서 i-2를 해준다.
처음 한변의 길이는 n과 같으므로 i=n으로 초기값을 설정하고, 길이가 0보다 클때까지 반복한다.
나선형으로 순회할때는 이렇게 가장 큰 사각형안의 더 작은 사각형, 그 안의 더 작은 사각형.. 이런식으로 반복된다.
이렇게 배열의 길이를 이용하고, 또 길이가 한바퀴를 돌때마다 -2가 된다는 것이 이 문제의 핵심인것 같다고 생각했다.
4️⃣ 중첩 for문을 이용한 위치이동
// 오른쪽으로 이동
for (let j = 0; j < i; j++) {
result[row][col] = num++;
col++;
}
col--;
row++;
바깥쪽 for문이 배열의 길이 i를 이용한다고 하면, 안쪽은 중첩 for문을 이용해서 위치를 이동하면서 num의 값을 조정한다.
코드는 나선형이므로 오른쪽 - 아래 - 왼쪽 - 위쪽 순으로 반복되며
오른쪽으로 이동하는 코드를 예시로 보면 위의 코드와 같다.
위치의 이동을 위해서 j를 이용하고 j는 현재 이동할 칸수를 의미한다.
예시로 n이 4라고 하면, j는 0부터 0,1,2,3이 될것이다. (0 부터 i-1까지 반복하면서 숫자를 배치하고 총 이동할 칸수는 i만큼이다)
for문이 반복되면서 num에 1씩을 더하면서 위치가 이동되는데, 처음에는 오른쪽으로 이동해야하기때문에 col에만 +1씩 해준다.
result[0][0] = 1
result[0][1] = 2
result[0][2] = 3
result[0][3] = 4
for문이 반복되면서 위와 같이 값이 들어가고, j=4가되면 i와 같이지므로 반복을 중단하고 for문을 빠져나온다.
이때 col은 안에서 이미 한번 더 더해줬기때문에 col의 인덱스 +1의 값이므로 바깥쪽에서 다시 한번 빼줘야 배열의 길이만큼으로 돌아온다.
그런 다음은 아래로 이동해야되기때문에 row에 +1을 해준다.
위와 같은 원리로 아래, 왼쪽, 위로 이동하는 코드를 모두 짜준다.
이때 주의해야 할 점은 나머지코드는 모두 비슷하지만 한변의 길이는 각각 다르기때문에 i의 길이가 줄어들었는지 아닌지를 반영하여 코드를 짜야한다.
아래와 왼쪽으로 이동할때는 길이가 1이 줄었기 때문에 j<i-1이 되고, 위로 이동할때는 길이가 2가 줄었기때문에 j<i-2가 된다.
이런식으로 위치를 이동하면서 num+을 해주며 i가 0보다 클때까지 반복된다.
💻 학습한 것
✔️ Array()와 Array.from()의 차이점
➡️Array()는 간단한 배열 생성이나 초기화에 사용되고, Array.from()은 기존 배열이나 이터러블 객체를 변환하거나 새로운 배열을 생성
Array(): 생성자 함수, 새로운 Array 객체를 생성
[element0, element1, ..., elementN]
new Array(element0, element1[, ...[, elementN]])
new Array(arrayLength)
Array()에 하나의 인자만 넣으면 배열의 길이를 나타낸다. 넣어준 숫자만큼의 length를 가진 Array가 생성된다.
Array.from(): 유사 배열 객체(array-like object)나 반복 가능한 객체(iterable object)를 얕게 복사해 새로운Array 객체를 생성
Array.from(arrayLike[, mapFn[, thisArg]])
mapFn
배열의 모든 요소에 대해 호출할 맵핑 함수.
Array.from()의 두번째 인자로 함수를 넣을 수 있다.
콜백 함수를 제공할 경우, 이 함수는 새로 생성된 배열의 각 요소에 대해 실행되며, 요소의 값을 결정한다.
✔️ n x n 2차원 배열만들기
Array.from(Array(n), () => Array(n))
Array(n)을 이용해서 length가 n인 배열을 만들고 Array.from의 두번째 인자로 함수를 넣어서 n x n의 2차원 배열을 생성할 수 있다.
🙋♀️ 내생각
배열을 나선형으로 만들거나 2차원배열을 만드는 것 모두 약간 생소해서 풀기가 어려운 문제였는데, 나만 그랬던 건 아닌것같다.
다른 사람의 풀이를 보다가 제일 좋아요를 많이 받은 코드는 보면서 웃음 터짐 ㅋㅋㅋㅋ
일일이 노다가로 하나하나 값을 다 넣어서 푼 코드였다 ㅋㅋㅋㅋㅋㅋㅋㅋㅋ
댓글도 웃겼음 😇😇😇
'JavaScript > 알고리즘' 카테고리의 다른 글
프로그래머스 문자열 바꿔서 찾기 JS ( 값의 대치를 위해 map()사용하기 ) (0) | 2023.06.12 |
---|---|
프로그래머스 특정한 문자를 대문자로 바꾸기 JS (정규식 생성자와 replace(), replaceAll() ) (0) | 2023.06.12 |
프로그래머스 배열의 길이에 따라 다른 연산하기 JS ( if문, map() / 비트 XOR (^) 연산 ) (2) | 2023.06.09 |
프로그래머스 접미사인지 확인하기 JS ( endsWith() / slice()와 length차 이용하기 ) (2) | 2023.06.08 |
프로그래머스 A 강조하기 JS ( toLowerCase(), replace() / replace의 매개변수로 함수 / 문자클래스 [ ] , [^ ] ) (0) | 2023.06.07 |