https://school.programmers.co.kr/learn/courses/30/lessons/42889
프로그래머스
SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프
programmers.co.kr
import java.util.*;
class Solution {
public int[] solution(int N, int[] stages) {
int[] answer = {};
Stage[] stage = new Stage[N];
for(int i = 0 ;i<N;i++){
int finalI = i+1;
double clear = Arrays.stream(stages).filter(item-> item >= finalI).toArray().length;
if(clear==0){
stage[i]=new Stage(finalI,0);
}else{
stage[i] = new Stage(finalI,
Arrays.stream(stages).filter(item -> item == finalI).toArray().length / clear);
}
}
return Arrays.stream(stage).sorted(Comparator.comparingDouble(Stage::getRate).reversed().thenComparing(Stage::getNumber)).mapToInt(Stage::getNumber).toArray();
}
class Stage{
private int number;
private double rate;
public Stage(int number,double rate){
this.number = number;
this.rate = rate;
}
public int getNumber(){
return this.number;
}
public double getRate(){
return this.rate;
}
}
}
다음과 같이 코드를 작성하였는데, 그림으로 내가 어떻게 생각하고 풀었는지 설명을 붙이도록 하겠다.

다음과 같이 Stage별로 저장할 데이터 구조를 만들어서, 현재 Stage번호랑, 실패율을 담아두어서 저장하도록 하였다.
for문을 돌고 나면 대충 결과가 아래와 같이 나오게 될 것이다.

이제 이 상태로 Steam을 이용하여 결과를 도출해 낼 것이다.
코드는 아래와 같다
return Arrays.stream(stage).sorted(Comparator.comparingDouble(Stage::getRate).reversed()
.thenComparing(Stage::getNumber)).mapToInt(Stage::getNumber).toArray();
이 길고 보기 힘든 코드를 설명해 보도록 하겠다.
stream(stage)를 통해서 스트림을 생성해주었다.
sorted(Comparator.comparingDouble(Stage::getRate).reversed() ...
부분은 먼저 보면
sort의 정렬 방법을 나타낸 것이다. Stage에 있는 Rate를 기준으로 내림차순으로 정렬하겠다는 의미이다
그 다음
.thenComparing(Stage::getNumber))
부분은 Rate가 같은 경우 다음 정렬 기준을 나타낸 것이다.
Number기준으로 오름차순으로 정렬을 한다(Stage가 작은 것부터 오름차순으로 하겠다는 뜻이다)
그 int형 배열로 반환하기 위해서
mapToInt(Stage::getNumber)를 통해서 stage의 번호를 가지고 intStream으로 바꿔준 후에
toArray();
int형 배열로 최종 반환한다.
맞다. 이 코드는 굉장히 더럽고 steam도 두 번 사용하기에 좋은 코드는 아닌 것 같다.
내가 이 코드를 작성하고도 테스트를 성공하지 못한 쉽지만 놓치기 쉬운 부분도 말하려고 한다.
Int / Int 는 실패율을 0 or 1 로 return한다.
나는 처음에 당연히 스테이지에 도달한 플레이어수를 나눌 때 int로 두고 나누었었다. 그러고 나니 Rate가 제대로 구해지지 않아서 계속 테스트가 틀렸던 것이었다.
int / double을 통해서 실패율을 구해주어야한다...
정답 코드
어떤 식으로 교재에 나와있는 지 좀 살펴보도록 하겠다.
import java.util.*;
class Solution {
public int[] solution(int N, int[] stages) {
int[] challenger = new int[N+2];
for(int i=0; i<stages.length ;i++){
challenger[stages[i]] += 1;
}
double total = stages.length;
HashMap<Integer,Double> fails = new HashMap<>();
for(int i = 1; i <= N ; i++){
if(challenger[i]==0){
fails.put(i,0.);
}else{
fails.put(i,challenger[i]/total);
total -= challenger[i];
}
}
return fails.entrySet().stream().sorted((o1,o2)->Double.compare(o2.getValue(),o1.getValue())).mapToInt(HashMap.Entry::getKey).toArray();
}
}
이것도 그림을 한번 그려보면서 설명을 해보겠다.
예제는 N=5일때이고, stages = [2, 1, 2, 6, 2, 4, 3, 3]

먼저 challenger배열에 각 stage에 몇명이 지금 있는지를 나타낸다. 0스테이지는 없기 때문에 0은 사용하지 않는 요소이다.
그리고 6은 모든 stages를 통과한 사람의 수이다.
total은 double형으로 저장해준다.
위에서 말했던 것 처럼 int/int 는 0 또는 1을 줄 수 밖에 없을 것이다.
그 다음 각 스테이지를 순회하면서 HashMap에다가 실패율을 저장한다.
total은 실패율을 저장할 때마다, 현재 stage에 있던 user를 빼서 업데이트를 매번 해줘야한다.

이런식으로 HashMap에 저장이 되게 된다.
HashMap에서 Stream 사용법
return fails.entrySet().stream().sorted((o1,o2)->Double.compare(o2.getValue(),o1.getValue())).mapToInt(HashMap.Entry::getKey).toArray();
와 같이 HashMap에서 Stream을 사용하는 방법을 살펴보도록 하겠다.
fails.entrySet() 가 어떤 것인지 생각을 한참 해보았다.
그래서 내가 내린 것은 위의 그림을 이용해서 어떻게 되는건지 보겠다.
HashMap의 형태로 돼있던 저것을 키-값 쌍의 Set으로(빨간색 상자)로 묶어서 보겠다는 것이다.

그 다음 stream()으로 생성해서 본다.
sorted((o1,o2)->Double.compare(o2.getValue(),o1.getValue()))
는 정렬을 하는 것인데 Double 값을 비교하고, o1,o2에서 o2.getValue() , o1.getValue()를 통해서 내림차순으로 HashMap의 value값을 정렬한다.
mapToInt(HashMap.Entry::getKey).toArray();
이거는 getKey를 통해서 intStream으로 변환하고 int형 배열로 반환하는 과정이다.
'코팅테스트' 카테고리의 다른 글
| [코딩 테스트] 근손실 (feat. 백트래킹) (1) | 2025.01.25 |
|---|---|
| [코딩 테스트] 체스판 다시 칠하기 (4) | 2025.01.24 |
| [코딩 테스트] 방문 길이 (3) | 2025.01.08 |
| [코딩 테스트] 모의고사 (Feat. Math함수와 Stream의 max() 사용에 관하여) (4) | 2025.01.07 |
| [코딩테스트] 두 개 뽑아서 더하기 (Feat. Stream과 IntStream에 관하여..) (6) | 2025.01.07 |