본문 바로가기
프로그래밍/알고리즘 문제풀이

[pg] 프로그래머스 다트게임

by 노잼인간이라불립니다 2023. 8. 8.

1. 문제 정의

 총 3라운드의 다트게임이 진행 되는데, 형식은 다음과 같이 들어온다. ex) "1S*2T*3S"

 

숫자는 0~10까지 들어오고 S일경우 1제곱, D일경우 2제곱, T일경우 3제곱을 수에 곱해주고 *일경우에는 자신의 바로앞 점수 *2, 그리고 현재 점수 *2 를 하게 된다. #일 경우에는 현재 숫자 * -1 이다. *와 #은 있을수도 있고 없을 수도 있다.

 

2. 나의 시도

 처음에 문제를 풀 때에는 뭔가 가독성있게 풀려고 생각을 했는데, 생각해보니 정규표현식을 잘 알지 못해서, 그냥 생 if else문으로 문제를 해결했다. (빠르게 해결하고 더 좋은 풀이를 찾는 것이 목적이었기 때문에 중복코드를 제거하는 메서드 조차 만들지 않았다.) 그리고 다른사람의 풀이를 살펴보고, 정규표현식을 쓰는 법을 학습하여 내 나름대로의 로직을 통해 구현하였다.

 또한 *이 나올경우 이전에 숫자에 다시 *2 연산을 하기 위해 배열을 이용하여 각 라운드 별로 점수를 저장하는 방법도 있었지만, 나는 스택을 이용하는 풀이가 좋아보여서, 결과적으로는 정규표현식과 스택을 섞어서 나만의 로직을 만들었다.

 

3. code

풀이1

public class Solution {

    public static int solution(String dartResult) {
        /*
         * 최종결과값
         */
        int answer =0;

        /*
         * 문자열을 char로 쪼갬
         */
        char[] chars = dartResult.toCharArray();

        /*
         * 라운드는 총 3회여서 선언
         */
        int gameRound = 1;
        /*
         * char 인덱스
         */
        int index = 0;
        /*
         * *가 나오면 바로앞의 숫자도 *2 해야해서 preNum 저장해놓음.
         */
        int preNum = 0;
        /*
         * 현재 계산할 숫자
         */
        int currNum = 0;

        while (gameRound<4){

            /*
             * 숫자가 10일 경우 10과 index +2 해주기
             * 아닐경우에는 해당숫자와 index +1
             */
            if(chars[index] == '1' && chars[index+1] =='0'){
                currNum = 10;
                index+=2;
            }else if( chars[index] >='0' && chars[index]<='9'){
                currNum = Character.getNumericValue(chars[index]);
                index++;
            }

            /*
             * S일 경우 + * or #
             */
            if(chars[index] == 'S' ){
                index++;
                if (index < chars.length && chars[index] == '*'){
                    currNum = currNum*2;
                    answer += currNum + preNum;
                    index++;
                }else if (index < chars.length && chars[index] == '#'){
                    currNum = currNum * -1;
                    answer +=  currNum;
                    index++;
                }else{
                    answer += currNum;
                }

                /*
                 * D일경우 * or #
                 */
            } else if (chars[index] == 'D') {
                index++;
                currNum = currNum * currNum;
                if (index < chars.length && chars[index] == '*'){
                    currNum = currNum*2;
                    answer += currNum + preNum;
                    index++;
                }else if (index < chars.length && chars[index] == '#'){
                    currNum = currNum * -1;
                    answer +=  currNum;
                    index++;
                }else{
                    answer += currNum;
                }

                /*
                 * T일경우 * or #
                 */
            } else if (chars[index] == 'T') {
                index++;
                currNum = currNum * currNum * currNum;
                if (index < chars.length && chars[index] == '*'){
                    currNum = currNum*2;
                    answer += currNum + preNum;
                    index++;
                }else if (index < chars.length && chars[index] == '#'){
                    currNum = currNum * -1;
                    answer += currNum;
                    index++;
                }else{
                    answer += currNum;
                }

            }
            preNum = currNum;
            gameRound++;


        }
        return answer;
    }
}

풀이2

public class Solution2 {

    public static int solution(String dartResult) {
        /*
         * 라운드별 정규표현식
         */
        String reg = "([0-9]{1,2}[S|D|T][*|#]?)";

        /*
         * 정규표현식 패턴으로 pattern객체 만듬
         */
        Pattern pattern = Pattern.compile(reg);

        /*
         * pattern객체의 matcher 메서드를 통해 문자열과 정규표현식이 일치하는지 확인해주는 matcher 생성
         */
        Matcher matcher = pattern.matcher(dartResult);

        /*
         * 이전 점수를 저장할 스택
         */
        Stack<Integer> prev = new Stack<>();

        for (int i = 0; i < 3; i++) {
            /*
             * reg와 일치하는 문자열을 찾고 group()으로 가져온다. (1S2D*3T 일경우 1S만)
             */
            matcher.find();
            String group = matcher.group();

            Pattern localPattern = Pattern.compile("([0-9]{1,2})([S|D|T])([*|#]?)");
            Matcher localMatcher = localPattern.matcher(group);

            localMatcher.find();

            /*
             * 그룹별로 나눠진 것을 계산
             */
            int curr = (int) Math.pow(Integer.parseInt(localMatcher.group(1)), getPower(localMatcher.group(2)));
            String multiply = localMatcher.group(3);
            curr *= getMultiply(multiply);
            if (!prev.isEmpty() && getMultiply(multiply) != -1) {
                Integer pop = prev.pop();
                pop *= getMultiply(multiply);
                prev.push(pop);
            }
            prev.push(curr);
        }

        /*
         * 정답
         */
        int answer = 0;
        while (!prev.isEmpty()){
            answer+= prev.pop();
        }
        return answer;
    }

    private static int getPower(String power) {
        if (power.equals("S")) return 1;
        if (power.equals("D")) return 2;
        if (power.equals("T")) return 3;
        return 0;
    }

    private static int getMultiply(String group) {
        if (group.length() > 0) {
            if (group.equals("*")) {
                return 2;
            }
            if (group.equals("#")) {
                return -1;
            }
        }
        return 1;
    }

}

 

4. 깨달은 점

 역시 문자열의 패턴을 찾는다던가 하는 방식은 if-else문 보다는 정규표현식을 이용하는 것이 좀 더 효율적인 것 같다. 이번기회에 Pattern 클래스와 Matcher 클래스를 조금이나마 사용해보고 이해하여 정규표현식을 사용해봤는데, 완전히 암기는 하기 어렵지만 그때그때마다 찾아서 필요한 정규표현식을 만들정도의 기반은 마련한 것 같다.

 

참조

https://school.programmers.co.kr/learn/courses/30/lessons/17682