문제를 보자마자 생각한 해법은 이랬다.
1. 완주자와 완주하지 못한 사람들 이름을 key로 갖는 객체를 생성하고, 해당 key값을 갖는 사람 수를 count
2. 두 객체의 이름별 value값 비교
3. 다른 값이 나오는 이름이 answer
function solution(participant, completion) {
var answer = "";
let partiObj = new Object();
let compObj = new Object();
let fail = [];
let part = participant.filter((v) => !completion.includes(v));
answer = part[0];
participant.map((v) => {
partiObj[v] ? partiObj[v]++ : (partiObj[v] = 1);
if (partiObj[v] > 1) {
part.push(v);
}
});
completion.map((v) => {
compObj[v] ? compObj[v]++ : (compObj[v] = 1);
});
part.map((v) => {
part.map((v) => {
if (partiObj[v] - compObj[v] === 1) {
answer = v;
}
});
});
return answer;
}
정확성은 통과하나, 효율성 부문에서 통과하지 못했다는 점이 문제였다.
내 알고리즘을 보면 모든 이름을 탐색하기 때문에 적어도 2N번 만큼 탐색해야된다는 것이었다.
그래서 고민하던 중 다른 해법을 보게 되었다.
function solution(participant, completion) {
var answer = "";
completion[completion.length] = "";
var arr1 = participant.sort();
var arr2 = completion.sort();
for (let i = 0; i < arr1.length; i++) {
if (arr1[i] !== arr2[i]) {
answer = arr1[i];
}
}
return answer;
}
1) completion 배열이 participant 배열 길이보다 1짧기때문에 "" 하나 더해준다.
2) 두 배열을 정렬 후 비교
코드 길이도 확 줄었고, 무조건 N번만 탐색하기 때문에 내 알고리즘과 같은 O(N)의 알고리즘이더라도 훨씬 효율적이었다.
var solution = (participant, completion) =>
participant.find(
(name) => !completion[name]--,
completion.map((name) => (completion[name] = (completion[name] | 0) + 1))
);
완주자 배열을 {이름:완주자배열에 등장하는 횟수}로 맵핑하고, 그 맵에 참가자 이름 하나씩 넣어서 찾아볼때마다 횟수 떨어뜨려서 횟수 0 나오는 걸 찾는 함수이다.
마지막 코드는 어떤 고수분이 정리하신 코드.. 이렇게까지 작성할 수 있는 날이 올때까지 노력해야겠다.