백준 2563번을 풀어보았다.
처음 풀었을 때는 지나치게 수학적으로만 접근하려고 해서 엄청 헤맸던 문제인데,
색종이가 붙은 격자는 1, 붙지 않은 격자는 0으로 한 뒤 1의 개수만 구하면 된다.
let [N, ...input] = require('fs').readFileSync('/dev/stdin').toString().split('\n').map((value) => value.trim())
N = Number(N)
input = input.map((value) => value.split(' ').map(Number))
let board = new Array(100).fill(null).map(() => new Array(100).fill(0));
for (let i = 0; i < N; i++) {
for (let r = input[i][1]; r < input[i][1] + 10; r++) {
for (let c = input[i][0]; c < input[i][0] + 10; c++) {
board[r][c] = 1
}
}
}
let area = 0
board.forEach((r) => {
r.forEach((c) => {
area += c
})
})
console.log(area)
위 코드를 작성하며 범했던 작은 실수 두 가지와 큰 실수 한 가지를 정리해보고자 한다.
1. 자료형에 유의하자.
앞서 많이 했던 실수인데 또 했다.
input = input.map((value) => value.split(' ')) 으로 하니 input[i][1] + 10이 17이 아닌 '710'이 되더라.
반드시! 활용될 형태로 변수의 자료형을 변환하자.
2. 극단적인 예시를 들어보자.
처음에는 반복문의 범위를 for (let c = input[i][1] - 1; c < input[i][1] + 9; c++) 로 설정하였다.
보통 인덱스는 1을 빼주곤 하니 큰 고민 없이 작성했던 건데
입력의 첫 번째 자연수가 0인 경우를 생각해보니 board[r][0]이 1이 되어야 하므로 1을 뺄 필요가 없었다.
극단적인 예시를 통해 문제 상황을 정확히 이해하고 예외를 발견하자.
3. JavaScript에서 객체는 참조형 데이터이다.
3번이 내가 한 제일 큰 실수였다.
처음에는 board를 아래와 같이 초기화하였다.
let row = new Array(100).fill(0)
let board = new Array(100).fill(row)
그동안 습관적으로 반복문만 사용하던 내가 fill 메소드를 떠올린 건 아주 잘했지만 이후 색종이가 붙은 격자를 1로 설정하는데,
이상하게도 열은 제대로 바뀌지만 행은 자꾸 모든 행이 동일하게 바뀌는 거다.
JavaScript에서 객체는 참조형 데이터이다.
즉, 객체를 변수로 설정하면 해당 변수에 데이터 값이 아닌 데이터 주소가 저장된다.
따라서 row는 0이 100개인 배열 그 자체가 아니라 row의 주소를 저장하고 있으며, board의 각 행은 동일한 row를 참조하게 된다.
그러니 board[r][c] = 1 을 통해 특정 행을 바꾸려고 해도 모든 행이 같이 바뀌었던 것이다.
사실 모든 행은 하나의 변수였으니 말이다.
원하는 대로 동작하도록 하려면 아래와 같이 수정해야 한다.
let board = new Array(100).fill(null).map(() => new Array(100).fill(0));
각 행마다 새로운 배열을 생성하므로 각 행이 별개의 배열을 참조하게 된다.
💫 이 문제를 통해 배운 것
• 활용될 형태로 변수의 자료형을 변환하자.
• 극단적인 예시를 통해 문제 상황을 정확히 이해하고 예외를 발견하자.
• JavaScript에서 객체는 참조형 데이터이다.