1. 문제
프로그래머스
코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.
programmers.co.kr
2. 풀이 과정
- 학생들의 찍는 규칙을 먼저 정리해봤다
- 학생 1: {1, 2, 3, 4, 5} 반복
- 학생 2: {2, 1, 2, 3, 2, 4, 2, 5} 반복
- 학생 3: {3, 3, 1, 1, 2, 2, 4, 4, 5, 5} 반복
- 시험문제와 학생의 찍는 패턴을 비교해서 각각 채점하는식으로 문제를 풀면 될 것 같다.
- 학생의 찍는 패턴은 배열 3개로 저장
- 3개의 count 변수를 통해 세 학생의 맞은 갯수 저장
- 그렇게 세 학생의 맞은 갯수를 저장 한뒤 비교해서 제일 많이 맞은 학생을 결과로 반환하면 된다.(중복 시 여러명 모두)
3. 내 코드
import java.util.*;
class Solution {
public int[] solution(int[] answers) {
int[] result = {};
// 세 학생의 찍는 패턴 배열로 저장
int[] stu1 = {1, 2, 3, 4, 5};
int[] stu2 = {2, 1, 2, 3, 2, 4, 2, 5};
int[] stu3 = {3, 3, 1, 1, 2, 2, 4, 4, 5, 5};
// 세 학생의 맞은 문제 count 변수
int stu1_cnt = 0;
int stu2_cnt = 0;
int stu3_cnt = 0;
for(int i = 0; i < answers.length; i++) {
// 1. 학생1 정답여부 체크
if(stu1[i % 5] == answers[i]) {
stu1_cnt++;
}
// 2. 학생2 정답여부 체크
if(stu2[i % 8] == answers[i]) {
stu2_cnt++;
}
// 3. 학생3 정답여부 체크
if(stu3[i % 10] == answers[i]) {
stu3_cnt++;
}
}
// 1등이 몇명인지 결정되지 않기 때문에 동적으로 할당하기 위해 리스트 사용
ArrayList<Integer> temp = new ArrayList<>();
if(stu1_cnt > stu2_cnt) { // 1이 2보다 큰 경우
if(stu1_cnt > stu3_cnt) { // 1이 3보다 큰 경우
// stu1 1등
temp.add(1);
} else if(stu1_cnt == stu3_cnt) { // 1과 3이 같은 경우
// stu1,3 공동 1등
temp.add(1);
temp.add(3);
} else { // 3이 1보다 큰 경우
// stu3 1등
temp.add(3);
}
} else if(stu1_cnt == stu2_cnt) { // 1과 2가 같은 경우
if(stu1_cnt > stu3_cnt) { // 1,2가 3보다 큰경우
// stu1,2 공동 1등
temp.add(1);
temp.add(2);
} else if(stu1_cnt == stu3_cnt) { // 1,2가 3과 같은 경우
// stu 1, 2, 3 공동 1등
temp.add(1);
temp.add(2);
temp.add(3);
} else { // 3이 1,2보다 큰 경우
// stu3 1등
temp.add(3);
}
} else { // 2가 1보다 큰 경우
if(stu2_cnt > stu3_cnt) { // 2가 3보다 큰 경우
// stu2 1등
temp.add(2);
} else if(stu2_cnt == stu3_cnt) { // 2와 3이 같은 경우
// stu2,3 공동 1등
temp.add(2);
temp.add(3);
} else { // 3이 2보다 큰 경우
// stu3 1등
temp.add(3);
}
}
return temp.stream().mapToInt(Integer::intValue).toArray();
}
}
시간복잡도
- O(N): 문제 갯수에 대한 1중 for문만 사용됨
4. 다른 정답 코드와 비교
프로그래머스 최다 좋아요 코드
import java.util.ArrayList;
class Solution {
public int[] solution(int[] answer) {
int[] a = {1, 2, 3, 4, 5};
int[] b = {2, 1, 2, 3, 2, 4, 2, 5};
int[] c = {3, 3, 1, 1, 2, 2, 4, 4, 5, 5};
int[] score = new int[3];
for(int i=0; i<answer.length; i++) {
if(answer[i] == a[i%a.length]) {score[0]++;}
if(answer[i] == b[i%b.length]) {score[1]++;}
if(answer[i] == c[i%c.length]) {score[2]++;}
}
int maxScore = Math.max(score[0], Math.max(score[1], score[2]));
ArrayList<Integer> list = new ArrayList<>();
if(maxScore == score[0]) {list.add(1);}
if(maxScore == score[1]) {list.add(2);}
if(maxScore == score[2]) {list.add(3);}
return list.stream().mapToInt(i->i.intValue()).toArray();
}
}
- 내 코드와 비교해봤을 때 전체적인 성능 차이(O(N))는 크게 보이진 않지만 학생들 간의 등수를 매기는 부분에
대해 가독성에서 차이가 좀 있는 것 같다.
// 1등이 몇명인지 결정되지 않기 때문에 동적으로 할당하기 위해 리스트 사용
ArrayList<Integer> temp = new ArrayList<>();
if(stu1_cnt > stu2_cnt) { // 1이 2보다 큰 경우
if(stu1_cnt > stu3_cnt) { // 1이 3보다 큰 경우
// stu1 1등
temp.add(1);
} else if(stu1_cnt == stu3_cnt) { // 1과 3이 같은 경우
// stu1,3 공동 1등
temp.add(1);
temp.add(3);
} else { // 3이 1보다 큰 경우
// stu3 1등
temp.add(3);
}
} else if(stu1_cnt == stu2_cnt) { // 1과 2가 같은 경우
if(stu1_cnt > stu3_cnt) { // 1,2가 3보다 큰경우
// stu1,2 공동 1등
temp.add(1);
temp.add(2);
} else if(stu1_cnt == stu3_cnt) { // 1,2가 3과 같은 경우
// stu 1, 2, 3 공동 1등
temp.add(1);
temp.add(2);
temp.add(3);
} else { // 3이 1,2보다 큰 경우
// stu3 1등
temp.add(3);
}
} else { // 2가 1보다 큰 경우
if(stu2_cnt > stu3_cnt) { // 2가 3보다 큰 경우
// stu2 1등
temp.add(2);
} else if(stu2_cnt == stu3_cnt) { // 2와 3이 같은 경우
// stu2,3 공동 1등
temp.add(2);
temp.add(3);
} else { // 3이 2보다 큰 경우
// stu3 1등
temp.add(3);
}
}
내 코드: 나의 경우 if문으로 모든 케이스를 정의해서 등수를 매겼다.(제일 단순한 방식)
int maxScore = Math.max(score[0], Math.max(score[1], score[2]));
ArrayList<Integer> list = new ArrayList<>();
if(maxScore == score[0]) {list.add(1);}
if(maxScore == score[1]) {list.add(2);}
if(maxScore == score[2]) {list.add(3);}
프로그래머스 코드: 먼저 최댓값을 뽑아낸 뒤, 그 값과 같은 점수를 갖은 학생만 따로 배열에 넣어주었다.
프로그래머스 코드대로 짜는 것이 나중에 문제가 학생 3명이 아닌 4명, 5명이 되어도 쉽게 답을 구할 수 있다.
(물론 최댓값 구하는 코드는 수정되어야 함)
---
추가적으로, 저 프로그래머스 코드에서도 한 가지 수정할만한 부분이 있다.(필수는 아님)
return list.stream().mapToInt(i->i.intValue()).toArray();
바로 스트림을 이용해서 list --> array로 변환하는 부분인데
이 코드의 댓글을 보면 해당 코드가 오래걸린다는 얘기가 있는데 그 이유는 다음과 같다고 한다.
스트림을 사용하는 것이 시간적으로는 좋지 않다는 것이다.
대신 다음과 같이 for문을 이용해서 바꾸는 방법이 더 빠르다는 이야기이다.
int[] answer = new int[list.size()];
int cnt = 0;
for(int num : list)
answer[cnt++] = num;
return answer;
과연 이게 사실일까?
그래서 검색해본 결과 어느정도 틀린말은 아니었다.
👀[JAVA] For과 Stream은 어떤 차이가 있는걸까?
코테를 풀때 나는 보통 원시 For문을 활용해서 반복문을 처리하는 경우가 많았다! 이유는... 스트림에 대해서 잘 몰랐기 때문! 그런데 다른 사람의 풀이를 살펴보다보면 stream이라는 api를 통해 아
velog.io
해당 블로그에 설명이 잘나와있다.
결론만 얘기하자면 성능은 For문 가독성은 Stream인 것 같다.
그렇게 유의미한 차이는 아닌것 같지만. 그래도 혹시 모르니까 for문이 낫지 않을까 하는게 내 생각이다.
5. 피드백
- 배열에서 최댓값 혹은 최솟값을 가진 인덱스를 모두 뽑아내야 한다면 최댓값(or 최솟값)을 한번 찾은 뒤,
다시 그 배열을 돌아 그 값을 가진 인덱스를 뽑는 식으로 접근하는 것이 좋다. - ArrayList와 같은 컬렉션 객체를 배열로 변환할 때 for문을 사용하는 방식, stream을 사용하는 방식이 있는데
for문은 성능이 조금더 좋고 stream은 가독성이 좋다.
코딩테스트 레벨에서는 for문을 쓰자.
'코딩 테스트 > 프로그래머스' 카테고리의 다른 글
[프로그래머스] 올바른 괄호 (0) | 2024.04.28 |
---|---|
[프로그래머스] 방문 길이 (0) | 2024.04.27 |
[프로그래머스] 실패율 (0) | 2024.04.27 |
[프로그래머스] 행렬의 곱셈 (0) | 2024.04.26 |
[프로그래머스] 두 개 뽑아서 더하기 (0) | 2024.04.25 |