문제 설명
수포자는 수학을 포기한 사람의 준말입니다. 수포자 삼인방은 모의고사에 수학 문제를 전부 찍으려 합니다. 수포자는 1번 문제부터 마지막 문제까지 다음과 같이 찍습니다.
1번 수포자가 찍는 방식: 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, ...
2번 수포자가 찍는 방식: 2, 1, 2, 3, 2, 4, 2, 5, 2, 1, 2, 3, 2, 4, 2, 5, ...
3번 수포자가 찍는 방식: 3, 3, 1, 1, 2, 2, 4, 4, 5, 5, 3, 3, 1, 1, 2, 2, 4, 4, 5, 5, ...
1번 문제부터 마지막 문제까지의 정답이 순서대로 들은 배열 answers가 주어졌을 때, 가장 많은 문제를 맞힌 사람이 누구인지 배열에 담아 return 하도록 solution 함수를 작성해주세요.
제한 조건
- 시험은 최대 10,000 문제로 구성되어있습니다.
- 문제의 정답은 1, 2, 3, 4, 5중 하나입니다.
- 가장 높은 점수를 받은 사람이 여럿일 경우, return하는 값을 오름차순 정렬해주세요.
입출력 예
answers | return |
[1,2,3,4,5] | [1] |
[1,3,2,4,2] | [1,2,3] |
입출력 예 #1
- 수포자 1은 모든 문제를 맞혔습니다.
- 수포자 2는 모든 문제를 틀렸습니다.
- 수포자 3은 모든 문제를 틀렸습니다.
따라서 가장 문제를 많이 맞힌 사람은 수포자 1입니다.
입출력 예 #2
- 모든 사람이 2문제씩을 맞췄습니다.
[풀이]
function solution(answers) {
const result = [];
const firstPerson = [1, 2, 3, 4, 5];
const secondPerson = [2, 1, 2, 3, 2, 4, 2, 5];
const thirdPerson = [3, 3, 1, 1, 2, 2, 4, 4, 5, 5];
const score = [0, 0, 0];
for (let i = 0; i < answers.length; i++) {
if (answers[i] === firstPerson[i % firstPerson.length]) score[0]++;
if (answers[i] === secondPerson[i % secondPerson.length]) score[1]++;
if (answers[i] === thirdPerson[i % thirdPerson.length]) score[2]++;
}
const maxScore = Math.max(...score);
for (let i = 0; i < score.length; i++) {
if (maxScore === score[i]) result.push(i + 1);
}
return result;
}
1. 이번 문제는 이해하는데도 좀 시간이 걸렸다.
3명의 수포자가 답을 찍는데 일정한 순서가 있다. 그것을 배열 안에 담아준다.
그리고 그 배열을 돌 때마다 정답(answers)과 일치 할 때 1점씩 올리기 위해 score 변수를 만들었다.
2. for문을 이용해 answers와 비교할 것이기 때문에 answers의 길이까지 반복해준다.
for문 안에서 3개의 if문을 사용했다. 정답의 인덱스 값과 수포자 배열의 인덱스 값을 배열의 길이로 나눈 나머지값과 비교했을 때
일치하면 스코어 점수를 1점씩 추가해준다.
예시)
수포자 1번 [1, 2, 3, 4, 5]가 계속 반복된다. 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, ...
answers = [1, 3, 2, 4, 2] 일 때 수포자 1번과 비교해야 한다.
1) i = 0 일 때
answers[0] = 1
firstPerson[0 % 5] = firstPerson[0] = 1
따라서 일치한다. 그래서 score = 1
2) i = 1 일 때
answers[1] = 2
firstPerson[1 % 5] = firstPerson[1] = 3
일치하지 않는다. 그래서 여전히 score = 1
이 과정을 수포자 2번, 3번도 똑같이 반복해준다.
이때 수포자[i % 수포자배열의길이] 를 해주는 이유는
만약 수포자 1번을 대상으로 반복했을 때
firstPerson[5 % 5] = firstPerson[0] = 1 이므로 다시 반복하게 해준다.
결국 1, 2, 3, 4, 5 를 거쳐 다시 1, 2, 3, 4, 5, ... 가 나오게 되는 것이다.
3. 반복문을 끝낸 후 score 배열을 Math.max()를 이용해 최대값을 구해준다.
이유는 가장많이 맞춘 사람이 누구인지 리턴해야하기 때문이다. 즉, score = [ 1번이 맞춘 갯수, 2번, 3번] 이 된다.
4. 마지막으로 for문을 이용해 최대점수(maxScore)값이 score의 인덱스 값과 같다면 result 배열에 i + 1 을 더해 리턴해준다.
예시)
answers = [1, 3, 2, 4, 2] 일 때
수포자 1번은 [1, 2, 3, 4, 5]를 반복해 [1, 4] 정답
수포자 2번은 [2, 1, 2, 3, 2, 4, 2, 5]를 반복해 [2, 2] 정답
수포자 3번은 [3, 3, 1, 1, 2, 2, 4, 4, 5, 5]를 반복해 [3, 2] 정답
따라서 for문을 이용해 얻은 score = [2, 2, 2]이다.
maxScore = Math.max(...score)이므로 Math.max(2, 2, 2)가 되어 최대점수는 2가 된다.
두번째 for문에서
maxScore가 score[i]값과 같을 때 result.push( i + 1 )이므로
1) i = 0,
maxScore === score[0] 은 2 === 2 이므로 result.push( 0 + 1 )이므로 result[1] 이 추가
2) i = 1,
maxScore === score[1] 은 2 === 2 이므로 result.push( 1 + 1 )이므로 result[2] 이 추가
3) i = 2,
maxScore === score[2] 은 2 === 2 이므로 result.push( 2 + 1 )이므로 result[3] 이 추가
따라서 result = [1, 2, 3]이 리턴된다.
[코드 리뷰]
function solution(answers) {
const result = [];
// 모든 패턴을 각각의 변수가 아닌 하나의 배열로 관리
const patterns = [
[1, 2, 3, 4, 5],
[2, 1, 2, 3, 2, 4, 2, 5],
[3, 3, 1, 1, 2, 2, 4, 4, 5, 5],
];
const scores = [0, 0, 0];
// 각각의 경우를 하드코딩하는게 아닌 반복문으로 개선
answers.forEach((answer, i) => {
patterns.forEach((pattern, j) => {
if (answers[i] === pattern[i % pattern.length]) {
scores[j]++;
}
});
});
const maxScore = Math.max(...scores);
// 이 부분은 그냥 위에서 forEach를 써서 일관성을 위해 리팩토링 했습니다.
scores.forEach((score, i) => {
if (maxScore === score) result.push(i + 1);
});
return result;
}
[추가 풀이]
1. 적절히 기능 별 함수로 분리까지 진행
function solution(answers) {
const patterns = [
[1, 2, 3, 4, 5],
[2, 1, 2, 3, 2, 4, 2, 5],
[3, 3, 1, 1, 2, 2, 4, 4, 5, 5],
];
const counters = getCounters(answers, patterns);
const maxNum = Math.max(...counters);
return getResult(counters, maxNum);
}
function getCounters(answers, patterns) {
return patterns.map((pattern) => {
return answers.filter((answer, j) => answer === pattern[j % pattern.length])
.length;
});
}
function getResult(counters, maxNum) {
return counters.reduce((acc, cur, i) => {
if (cur === maxNum) acc.push(i + 1);
return acc;
}, []);
}
/**
* (풀이)
* 해당 문제는 수포자1, 2, 3 학생들의 각각의 정답 패턴을 미리 선언한다.
* 그리고 answers를 순회하면서 2중 forEach로 patterns도 순회해 answer과 pattern를 비교해 정답일 때를 찾는다.
* 만약, 정답을 맞춘다면 맞췄을 때 학생 인덱스를 counters 인덱스에 대응해 값을 증가시킨다.
* 그리고 가장 많이 맞춘 사람을 고르는 것이기 때문에 (중복 허용) Math.max를 구해서 많이 맞춘 횟수를 찾고,
* reduce를 이용해 maxNum과 같은 학생을 모은 배열을 리턴함으로써 풀었다.
*/
'코딩 테스트 > Programmers - 1' 카테고리의 다른 글
[JS] 체육복 (0) | 2022.10.13 |
---|---|
[JS] 폰켓몬 (0) | 2022.10.06 |
[JS] x만큼 간격이 있는 n개의 숫자 (0) | 2022.10.04 |
[JS] 하샤드 수 (1) | 2022.10.04 |
[JS] 정수 내림차순으로 배치하기 (0) | 2022.10.04 |