Midnight Coder's Lounge

[JavaScript] .slice()에 음수를 넣을 땐 0을 조심하세요 (백준 18110 solved.ac 3% 반례) 본문

Algorithm

[JavaScript] .slice()에 음수를 넣을 땐 0을 조심하세요 (백준 18110 solved.ac 3% 반례)

AtomicLiquors 2025. 2. 20. 13:48

 요약 

- 배열을 자르는 메서드에 .slice(-N), .splice(-N)처럼 음수 인덱스를 넣으면, 배열 맨 끝에서 N번째 항목을 가리키게 할 수 있다.

- 하지만 N = 0이라면? 배열 맨 끝이 아니라 맨 처음을 가리키게 된다. .slice(-N) = .slice(-0) = .slice(0)이기 때문이다.

 

 


 

 상세 

JavaScript로 백준 18110번 문제 "solved.ac"를 풀고 있었습니다. 주어진 N의 15%에 해당하는 갯수만큼 배열에서 최댓값 / 최솟값을 각각 제외하고 나머지 수들에 대해 평균을 내는 문제입니다. 그렇기 때문에 입력받은 배열을 정렬하고, N의 15%에 해당하는 값(변수명 offset)만큼 배열의 앞뒤에서 slice하는 방식으로 문제를 풀고자 합니다.

 

 

따라서 다음과 같이 코드를 작성했습니다.

/* 오답 코드 */
const fs = require('fs');
const input = fs.readFileSync(0, 'utf-8').trim().split('\\n');

const N = Number(input[0]);
if(N === 0){
    console.log(0);
    return;
}
    
const offset = Math.round(N * 0.15);
const difficulties = input.slice(1, N+1).map(Number).sort((a, b) => a - b);
const sliced = difficulties.slice(offset, -offset);
const sum = sliced.reduce((acc, e) => acc + e, 0);
console.log(Math.round(sum / (N - offset * 2)));

 

[제출 결과]

3%에서 오답이 나옵니다.

 

 

반올림 연산을 잘못한 건가? 평균값을 잘못 구한 건가?
한참 엉뚱한 데서 반례를 찾다가 결국 아래 코드에 문제가 있다는 걸 알게 되었습니다.

const sliced = difficulties.slice(offset, -offset);

 

 

N의 15%가 0이 되는 경우 변수 offset의 값은 0이 됩니다.
예를 들면, 다음과 같이 N이 3인 반례를 들 수 있겠습니다.

 

[반례]

3
1
2
3

[정답]

2 // slice의 결과는 [1, 2, 3]이 되고 출력 결과는 (1 + 2 + 3) / 3 = 2가 되어야 한다.

[오답]

0 // slice의 결과는 빈 배열 []이 되고 출력 결과는 0으로 나오고 있다.

 

원래 구상했던 로직대로라면 배열의 앞뒤에서 0만큼을 제외하고 나머지 부분에 대해 평균을 구해야 합니다.

문제는 offset의 값이 0이 되면  .slice(offset, -offset)  .slice(0, -0)  .slice(0, 0)  이 되어 버린다는 겁니다. "배열의 앞에서 0만큼 떨어져서 출발, 뒤에서 0만큼 떨어져서 끝"이 아니라, 그냥 0에서 시작해서 0에서 끝나 버리는 겁니다.

따라서  .slice(offset, -offset) 의 결과는 빈 배열 []가 되어 버립니다.

 

그렇기 때문에 문제가 되는 코드를 아래와 같이 고쳐야 합니다. 배열 길이인 N에서 offset을 뺀 값, 다시 말해 배열 끝에서 N만큼 떨어진 지점을 사용하겠다는 것을 JavaScript에게 확실하게 알려줘야 합니다.

const sliced = difficulties.slice(offset, N - offset); //-offset에서 N-offset으로 수정.

 

 

/* 정답 코드 */
const fs = require('fs');
const input = fs.readFileSync(0, 'utf-8').trim().split('\\n');

const N = Number(input[0]);
if(N === 0){
    console.log(0);
    return;
}
    
const offset = Math.round(N * 0.15);
const difficulties = input.slice(1, N+1).map(Number).sort((a, b) => a - b);
const sliced = difficulties.slice(offset, N - offset)
const sum = sliced.reduce((acc, e) => acc + e, 0);
console.log(Math.round(sum / (N - offset * 2)));

 

[제출 결과]

 

 

 

저는 한참 헤맸지만 멋쟁이 개발자이신 여러분은 이런 실수 때문에 버그를 내는 일이 없기를 바랍니다.

 

Comments