Task description
- 정수 N과 1 ~ N + 1까지의 값을 원소로 가지는 배열 A가 주어짐
- 배열 A를 순회하면서 해당 값들이 나오는 수를 카운트
- 배열 A를 순회하는 중에 발견된 값이 N + 1일 경우 모든 값에 대한 카운트를 가장 높은 카운트 수로 일괄 변경
즉,
N = 5
A[0] = 3
A[1] = 4
A[2] = 4
A[3] = 6
A[4] = 1
A[5] = 4
A[6] = 4
이러한 N과 A 배열이 주어졌다면,
A[2]까지 순회 했을 때 3은 1번, 4는 2번 카운트 되었으므로
(0, 0, 1, 2, 0)
이 반환되어야 하고,
이후 A[3]까지 순회 했을 때는 6 = N + 1에 해당하므로 모든 값에 대한 가장 높은 카운트
수인 2로 일괄 변경하여
(2, 2, 2, 2, 2)
가 반환되어야 함.
이를 처리하는 가장 효율적인 알고리즘 작성
How I did solve
1 차 (77%)
- 1부터 N까지 A에 몇 번 나타나는가가 일단 기본값을 이루기 때문에 카운터 Deck(?)을 만들어 두고 값 값이 나올때마다 Deck의 값을 1씩 증가.
- N + 1의 값이 나오면 모든 Deck을 가장 큰 카운터 값으로 채움
- 가장 큰 카운터 값을 그 때 그 때 조회하는건 비효율적이므로 값을 조회할 때마다 가장 큰 카운터 값을 미리 담아 둠.
- 최종적으로 반환 시에 Deck이 비어있으면 오류이므로 Deck의 각 카운트 값은 0으로 초기화.
이 요구사항으로 구현을 하고 제출했으나... 스코어 77%... 또르르...
large_random2과 extream_large 케이스에서 Timeout이 발생했다.
Solved Code
function solution(N, A) {
const counter = new Array(N).fill(0);
let maxCounter = 0;
A.forEach( item => {
let idx = item - 1;
if(item <= N) {
counter[idx] += 1;
maxCounter = Math.max(maxCounter, counter[idx]);
}
else
counter.fill(maxCounter)
})
return counter
}
2차
어디서 문제일까 되짚어 봤을 때, 아무래도
counter.fill(maxCounter)
이 부분에서
timeout을 일으킨듯 보여서 이 부분을 개선해보기로.
- N + 1이 나타날 때 마다 fill 하는 대신 max counter를 memorize해두고 마지막에 한 번에 적용
- 단, 이 경우 중간에 max counter로 변경되어 거기서부터 다시 1씩 증가시키는 경우는 결과값이 달라지므로, 증가 시킬 때 max counter와 memorized counter를 분리하여 max counter가 발생된 이후 반영된 적이 없으면 일반 변경시키고 증가 시키도록 구현
그리고 이렇게 해서 100% 달성!
Solved Code
function solution(N, A) {
const counter = new Array(N).fill(0);
let maxCounter = 0;
let tmpMaxCounter = 0;
A.forEach( (item) => {
let idx = item - 1;
if( item <= N) {
counter[idx] = Math.max(counter[idx], maxCounter);
counter[idx] += 1;
tmpMaxCounter = Math.max(counter[idx], tmpMaxCounter);
}else{
maxCounter = tmpMaxCounter;
}
});
counter.forEach( (item, idx, arr) => {
arr[idx] = Math.max(item, maxCounter);
})
return counter
}
Retrospective
- 하... 이 문제는 문제를 이해하는데만 거의 30분 이상을 쓴 것 같다.
영어를 떠나서 문제 설명을 이렇게 어렵게 해놓아서야... 허허허...
이 문제가 중급 난이도인건 문제 자체를 이해하는게 어려워서가 아닐까? - 역시 두 번만에 풀었음. 한 번에 풀어보고 싶다...
- 아직까지는 그래도 풀만 하다.