문제
풀이

💡 Idea

완전 탐색을 하는 쉬운 문제이다. 그런데 애먹은 부분이 있다면, 점수 계산을 끝낸 뒤에, 가장 높은 점수인 학생들을 모으는 과정이었다. 이 부분이 이 문제의 핵심 부분이 아닌데, 아래와 같이 코드가 길어지는 게 싫었다.

ArrayList<Integer> winners_list = new ArrayList<>();

int max_score = 0;

for(int i = 0; i < 3; i++){
	max_score = Math.max(scores[i], max_score);
}

for(int i = 0; i < 3; i++){
	if(scores[i] == max_score) winners_list.add(i+1);
}

int[] winners_array = new int[winners_list.size()];

for(int i = 0; i < winners_list.size(); i++){
	winners_array[i] = winners_list.get(i);
}

return winners_array;

그래서 문제를 푼 이후에 stream을 이용하여 코드를 줄여보았다. 아직 stream으로 생각하는 방식이 익숙하지 않아 바로 떠올리기가 쉽지 않았다.

int max_score = Arrays.stream(scores).max().orElse(0);
		
int[] winners = IntStream.range(0,3).filter(i -> scores[i] == max_score).map(i -> i+1).toArray();

return winners;

🔑 Code

import java.util.*;
import java.util.stream.IntStream;

class Solution {
    private static final int[][] rules = {
        {1, 2, 3, 4, 5},
        {2, 1, 2, 3, 2, 4, 2, 5},
        {3, 3, 1, 1, 2, 2, 4, 4, 5, 5}
    };
    
    public int[] solution(int[] answers) {
        int scores[] = {0,0,0};
        for(int i = 0; i < answers.length; i++){
            for(int j = 0; j < 3; j++){
                if(rules[j][i % rules[j].length] == answers[i]) scores[j]++;
            }
        }

        int max_score = Arrays.stream(scores).max().orElse(0);
                
        int[] winners = IntStream.range(0,3).filter(i -> scores[i] == max_score).map(i -> i+1).toArray();
        
        return winners;
    }
}

🗨️ Side Notes

람다식 내부에서 지역 변수를 사용하려면 그 변수는 final이거나 effectively final이어야 한다.

현재 코드는 가능하다.

int maxScore = Arrays.stream(scores)
        .max()
        .orElse(0);

return IntStream.range(0, scores.length)
        .filter(i -> scores[i] == maxScore)
        .toArray();

maxScore를 선언한 이후 다시 바꾸지 않았기 때문이다.

이런 변수를 effectively final이라고 한다.

다음 코드는 컴파일되지 않는다.

int maxScore = 0;

for (int score : scores) {
    maxScore = Math.max(maxScore, score);
}

return IntStream.range(0, scores.length)
        .filter(i -> scores[i] == maxScore)
        .toArray();

왜냐하면 maxScore가 반복문에서 계속 변경되기 때문이다.

컴파일러는 대략 다음과 같은 오류를 낸다.

Local variable maxScore defined in an enclosing scope
must be final or effectively final

이 경우 중간 변수를 하나 더 만들 수 있다.

int max = 0;

for (int score : scores) {
    max = Math.max(max, score);
}

int maxScore = max;

return IntStream.range(0, scores.length)
        .filter(i -> scores[i] == maxScore)
        .map(i -> i + 1)
        .toArray();

maxScore는 선언 후 변경되지 않으므로 람다에서 사용할 수 있다.

하지만 이 문제에서는 Stream으로 최댓값까지 구하면 더 간단하다.

int maxScore = Arrays.stream(scores)
        .max()
        .orElse(0);