[Programmers] 로또의 최고 순위와 최저 순위 - Java

2021. 12. 10. 20:30Computer Sciences/Problem Solve

https://programmers.co.kr/learn/courses/30/lessons/77484

 

코딩테스트 연습 - 로또의 최고 순위와 최저 순위

로또 6/45(이하 '로또'로 표기)는 1부터 45까지의 숫자 중 6개를 찍어서 맞히는 대표적인 복권입니다. 아래는 로또의 순위를 정하는 방식입니다. 1 순위 당첨 내용 1 6개 번호가 모두 일치 2 5개 번호

programmers.co.kr

풀이

문제 풀이의 핵심은 최고 순위는 매칭된 숫자 개수 + 0의 개수이고 최저 순위는 매칭된 숫자 개수라는 것이다. 2중 for 문으로 각 요소를 비교한 뒤에 0의 개수를 세는 식으로 다음과 같이 어렵지 않게 풀어낼 수 있다.

아래는 필자가 처음으로 해결했을 때 작성한 코드이다.

먼저 각 배열을 정렬한 후에 0의 개수를 세고 이중 for 문을 순회한다. 그리고 마지막에 0의 개수만큼 더해주어서 결과값을 반환한다.

import java.util.*;

class Solution {

    private static int LOTTOS_LENGTH = 6;

    public int[] solution(int[] lottos, int[] win_nums) {
        int[] answer = new int[2];
        int zeroCount = 0;
        int correctNumCount = 0;

        Arrays.sort(lottos);
        Arrays.sort(win_nums);

        for (int i = 0; i < LOTTOS_LENGTH; i++) {
            if (lottos[i] == 0) {
                zeroCount++;
            }
        }

        for (int i = 0; i < LOTTOS_LENGTH - zeroCount; i++) {
            for (int j = 0; j < LOTTOS_LENGTH; j++) {
                if (lottos[zeroCount + i] == win_nums[j]) {
                    correctNumCount++;
                    break;
                }
            }
        }

        if (zeroCount == 0) {
            answer[0] = answer[1] = calcRank(correctNumCount);
        } else {
            answer[0] = calcRank(correctNumCount + zeroCount);
            answer[1] = calcRank(correctNumCount);
        }

        return answer;
    }

    public int calcRank(int num) {
        switch (num) {
            case 6:
                return 1;
            case 5:
                return 2;
            case 4:
                return 3;
            case 3:
                return 4;
            case 2:
                return 5;
            default:
                return 6;
        }
    }
}

리팩토링

1. 정렬의 필요성

처음 생각했을 땐 0을 앞으로 모아서 처리하기 위해 정렬이 필요하다고 생각했다. 그러나 어차피 for 문을 돌면서 모두 비교할 것이라면 정렬할 필요가 없다는 것을 깨달았다. 그래서 정렬 부분은 제거한다.

2. 0 체크의 위치

0을 체크하는 것은 이중 for 문을 돌면서 해도 가능하다. 그런데 굳이 밖에서 for 문을 한 번 돌면서 체크할 이유가 없다. 이 또한 이중 for 문 안에 위치시키고 for 문을 제거한다.

3. 마지막 if 문의 필요성

다시 보면서 생각하니 zeroCount가 0이면 굳이 if 문으로 나눌 필요가 없다는 것을 깨달았다. 따라서 이 if 문 또한 제거한다.

리팩토링된 코드

class Solution {

    public int[] solution(int[] lottos, int[] win_nums) {
        int[] answer = new int[2];
        int zeroCount = 0;
        int correctNumCount = 0;

        for (int lotto : lottos) {
            if (lotto == 0) {
                zeroCount++;
                continue;
            }
            for (int win_num : win_nums) {
                if (lotto == win_num) {
                    correctNumCount++;
                }
            }
        }

        answer[0] = calcRank(correctNumCount + zeroCount);
        answer[1] = calcRank(correctNumCount);

        return answer;
    }

    public int calcRank(int num) {
        switch (num) {
            case 6:
                return 1;
            case 5:
                return 2;
            case 4:
                return 3;
            case 3:
                return 4;
            case 2:
                return 5;
            default:
                return 6;
        }
    }
}