
프로그래머스 152995 : 인사고과 - Javascript
문제 설명
완호네 회사는 연말마다 1년 간의 인사고과에 따라 인센티브를 지급합니다. 각 사원마다 근무 태도 점수와 동료 평가 점수가 기록되어 있는데 만약 어떤 사원이 다른 임의의 사원보다 두 점수가 모두 낮은 경우가 한 번이라도 있다면 그 사원은 인센티브를 받지 못합니다. 그렇지 않은 사원들에 대해서는 두 점수의 합이 높은 순으로 석차를 내어 석차에 따라 인센티브가 차등 지급됩니다.
이때, 두 점수의 합이 동일한 사원들은 동석차이며, 동석차의 수만큼 다음 석차는 건너 뜁니다. 예를 들어 점수의 합이 가장 큰 사원이 2명이라면 1등이 2명이고 2등 없이 다음 석차는 3등부터입니다.
각 사원의 근무 태도 점수와 동료 평가 점수 목록 scores이 주어졌을 때, 완호의 석차를 return 하도록 solution 함수를 완성해주세요.
제한사항
- 1 ≤
scores
의 길이 ≤ 100,000 scores
의 각 행은 한 사원의 근무 태도 점수와 동료 평가 점수를 나타내며 [a, b] 형태입니다.scores
[0]은 완호의 점수입니다.- 0 ≤ a, b ≤ 100,000
- 완호가 인센티브를 받지 못하는 경우 -1을 return 합니다.
입출력 예
scores | result |
---|---|
[[2,2],[1,4],[3,2],[3,2],[2,1]] | 4 |
-
5 번째 사원은 3 번째 또는 4 번째 사원보다 근무 태도 점수와 동료 평가 점수가 모두 낮기 때문에 인센티브를 받을 수 없습니다.
-
2 번째 사원, 3 번째 사원, 4 번째 사원은 두 점수의 합이 5 점으로 최고점이므로 1 등입니다.
-
1 등이 세 명이므로 2 등과 3 등은 없고 1 번째 사원인 완호는 두 점수의 합이 4 점으로 4 등입니다.
풀이 과정
전체 선수(participant) 중 완주한 선수(completion) 목록에 존재하지 않는 선수 한 명을 찾아내야 합니다.
시도 1
splice
와 indexOf
를 이용해 완주한 선수(completion)를 전체 선수(participant)에서 하나씩 소거한 뒤, 남은 한 선수의 이름을 반환하는 방식으로 풀어봤습니다.
function solution(scores) {
const len = scores.length;
for(let i = 1; i < len; ++i){
if(scores[0][1] < scores[i][0] && scores[0][1] < scores[i][1]){
return -1;
}
}
const totalScores = scores.map([a,b] => a + b);
}
하지만 정확도 테스트는 통과하고 시간 초과로 효율성 테스트는 통과하지 못했습니다. 배열을 수정하는 splice
가 느리기 때문에 생긴 문제인 듯 합니다.
시도 2
아래와 같이 해쉬를 이용해 문제를 다시 풀었고, 성공적으로 효율성 테스트까지 통과했습니다.
function solution(participant, completion) {
// 완주한 선수의 이름의 개수를 저장할 변수 선언
const counts = {};
// 완주한 선수의 이름의 개수를 `counts` 변수에 담기
for (name of completion) {
if (counts[name]) {
counts[name]++;
} else {
counts[name] = 1;
}
}
for (name of participant) {
if (counts[name]) {
counts[name]--; // 선수 이름이 있으면 개수 1 감소
} else {
return name; // 선수 이름이 없거나 0이면 해당 선수의 이름을 반환
}
}
}
숏코딩 (CodeGolf)
조금 더 코드를 간결하게 바꾸기 위해 조건식 부분을 수정해 아래와 같이 정리 가능합니다.
function solution(participant, completion) {
const counts = {};
for (name of completion) counts[name] = (counts[name] | 0) + 1;
for (name of participant) if (!counts[name]--) return name;
}
:::help counts
에 name
이 없을 수도 있는데 !counts[name]--
이 왜 제대로 작동하나요?
counts[name]
가 비어있을 경우 접근하면undefined
를 반환합니다.undefined
가 산술 연산자와 만나면 오류 없이NaN
으로 바뀌게 됩니다.NaN
은 논리값 거짓으로 변환되기 때문에,!NaN
은true
로 변환됩니다.
- 따라서
counts[name]
이 존재하지 않을 때,!counts[name]--
는true
으로 변환됩니다.
이러한 과정을 통해 매핑된 값이 없는 경우에도 선수의 이름을 반환하는 로직이 정상적으로 작동하게 됩니다.
:::
추가로 counts
객체 생성 라인을 제거하고 completion
배열을 해쉬맵 용도로 재사용합니다.
function solution(participant, completion) {
for (name of completion) completion[name] = (completion[name] | 0) + 1;
for (name of participant) if (!completion[name]--) return name;
}
:::help completion
는 배열인데 어떻게 키값을 인덱스로 사용 할 수 있나요?
- 자바스크립트에서는 배열 또한
Array
라는 객체이기 때문에 속성(property)을 추가할 수가 있습니다. - 따라서
completion[name]
이라는 코드가 정상적으로 작동하게 됩니다.
:::
for-of
를 map()
과 find()
메소드로 바꾸고 한줄의 코드로 합칩니다.
function solution(participant, completion) {
completion.map(name => (completion[name] = (completion[name] | 0) + 1));
return participant.find(name => !completion[name]--, completion);
}
solution = (participant, completion) =>
participant.find(
name => !completion[name]--,
completion.map(name => (completion[name] = (completion[name] | 0) + 1))
);
마지막으로 가독성을 포기하고 모든 이름을 한글자로 수정하면 아래와 같이 숏코딩 코드가 완성됩니다.
solution = (p, c) =>
p.find(
n => !c[n]--,
c.map(n => (c[n] = (c[n] | 0) + 1))
);