[프로그래머스] 모의고사 (완전탐색 Lv. 1) - 자바 Java
2021. 5. 5. 06:00ㆍ네카라쿠배 취준반 - 프로그래머스 문제 풀이/코딩 테스트 연습 - 해시
1. 문제 설명 (출처 : 프로그래머스)
수포자는 수학을 포기한 사람의 준말입니다. 수포자 삼인방은 모의고사에 수학 문제를 전부 찍으려 합니다. 수포자는 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문제씩을 맞췄습니다.
2. 문제 접근 방식 (문제 단순화 하기)
- 늘 그렇듯, 문제를 간단하게 만들어보는 것이 1단계이다.
- 완전 탐색 유형은 가장 단순하고 그래서 참 쉽다.
- 하나도 빠짐없이 모든 경우의 수를 확인하고 있는지만 확인하면 된다.
- 이 문제의 경우에는 각 수포자가 제출한 답안이, 실제 정답지와 몇 개 맞는지를 세면 되는 아주 간단한 문제이다.
3. 완전 탐색 솔루션
import java.util.*;
class Solution {
public static int[] solution(int[] answers) {
int[][] patterns = {
{1, 2, 3, 4, 5},
{2, 1, 2, 3, 2, 4, 2, 5},
{3, 3, 1, 1, 2, 2, 4, 4, 5, 5}
};
// 1. Count correct count per person
int[] hit = new int[3];
for(int personIdx = 0; personIdx < hit.length; personIdx++)
for(int probIdx = 0; probIdx < answers.length; probIdx++)
if(patterns[personIdx][probIdx % patterns[personIdx].length] == answers[probIdx])
hit[personIdx]++;
// 2. Find Max Count
int max = Math.max(hit[0], Math.max(hit[1], hit[2]));
// 3. Find Max Players
List<Integer> list = new ArrayList<>();
for(int i = 0; i < hit.length; i++)
if(max == hit[i])
list.add(i + 1);
// 4. Make answer array
int[] answer = new int[list.size()];
int cnt = 0;
for(int num : list)
answer[cnt++] = num;
return answer;
}
}
1) 각 사람 별 정답 수 계산하기
- 이 이중 루프는 personIdx와 probIdx별로 전부 돌면서 각 사람이 몇 개의 문제를 맞혔는지 계산하는 동작을 수행한다.
- 이 동작이 끝난 뒤의 hit 배열은 다음과 같은 모습이 된다. (1번 예제 기준)
2) hit[0], hit[1], hit[2] 중 max값 찾기
- 정답자 중 max 값을 확인해야만, max 값인 정답자들을 전부 반환할 수 있기 때문에 최댓값을 확인한다.
- 이 경우 max == 5가 된다.
- Math.max(a, b) : a와 b 중 더 큰 값을 반환해주는 함수이다.
3) Max값과 동일한 값을 가진 사람 찾기
- 이제 다시 hit 배열을 돌며 max값과 동일한 정답 수를 가진 사람을 찾아 list에 추가한다.
- 이렇게 해야만 max값으로 동점을 가진 사람을 전부 찾을 수 있게 된다.
4) 배열 형태로 변환하여 반환하기
- List는 추가/제거가 용이하여 개수가 정해지기 전에 사용하기 좋다.
- 하지만 답안은 배열 형태로 반환해야 되기 때문에 다시 배열로 변환해줘야 한다.
- 코드에서 보듯 List의 값을 하나씩 꺼내서 담아줄 수도 있지만, stream을 사용하여 다음과 같이 한 번에 변환할 수도 있다.
- 스트림은 '데이터의 흐름’입니다. 배열 또는 컬렉션 인스턴스에 여러 함수를 조합하여 원하는 결과를 필터링하고 가공된 결과를 얻을 수 있습니다.
- 또한 람다를 이용하여 코드를 간소화할 수 있습니다.
return list.stream().mapToInt(i->i.intValue()).toArray();
- list.stream() : 기존의 Integer List를 IntegerStream으로 변환하는 함수
- i -> i.intValue() : i라는 Integer 타입 변수가 있을 때, i.intValue() 형태로 primitve int 값을 추출하는 람다
- 람다란 한 줄짜리 간단한 함수(?) 정도로 이해하면 된다.
- list.stream().mapToInt(i->i.intValue()) : Integer List를 IntegerStream으로 변환하고, 해당 리스트의 모든 Integer 타입 값을 하나씩 (흐름으로) 람다를 태운다. 즉, Integer List의 모든 값을 int 형태 primitve 변수로 변환하여 그 '데이터 흐름'을 반환한다.
- list.stream().mapToInt(i->i.intValue()).toArray() : 바로 윗 단계에서 반환된 int 타입의 데이터 흐름을 Array로 변환한다.
- List에서 하나씩 get 하여 array에 담는 코드가 작성하기 쉽다는 장점이 있지만 코드가 길어진다면,
stream은 한 줄로 동일한 동작을 하여 코드가 매우 간결하지만, 생각보다 어려워하는 경우도 있다.
4. 참 쉽죠?
- 완전 탐색은 참 쉽다. 빠짐없이 모든 경우의 수를 다 따져보기만 하면 되는데, 컴퓨터는 이런 것을 하는 데 최적화되어있는 존재다.
- 이게 코딩 테스트 문제로 나와 한 사람의 취직을 결정하는 문제가 되기는 어렵지만,
이 정도 수준의 문제를 단순 버그 없이 한 번에 짤 수 있는지는 나의 구현 능력을 가늠하는 간단한 평가 정도는 될 것 같다. - 이런 문제 조차 한 번에 pass를 해내지 못한다면, 뛰어난 수학적 사고가 있다 할지라도 구현 능력이 부족하다는 것을 의미하니, 같은 문제라도 반복해서 풀며 한 번에 맞출 때까지 도전해 보는 것도 의미가 있다고 생각한다.
'네카라쿠배 취준반 - 프로그래머스 문제 풀이 > 코딩 테스트 연습 - 해시' 카테고리의 다른 글
[프로그래머스] 카펫 (완전탐색 Lv. 2) - 자바 Java (0) | 2021.05.18 |
---|---|
[프로그래머스] 소수 찾기 (완전탐색 Lv. 2) - 자바 Java (0) | 2021.05.07 |
[프로그래머스] 베스트 앨범 (해시 Lv. 3) - 자바 Java (0) | 2021.05.03 |
[프로그래머스] 위장 (해시 Lv. 2) - 자바 Java (4) | 2021.04.30 |
[프로그래머스] 전화번호 목록 (해시 Lv. 2) - 자바 Java (1) | 2021.04.28 |