본문 바로가기

컴퓨터/프로그래머스

프로그래머스 - 17682번: [1차] 다트 게임 [Java]

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

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

1. 코드

import java.util.*;
class Solution {
    public int solution(String dartResult) {
        int answer = 0;
        Stack <Integer> stack = new Stack<>();
        String[] s1 = dartResult.split("[^0-9]+");          //문자 사이에 있는 숫자로만 구성
        String[] s2 = dartResult.split("[0-9]+");           //숫자 사이에 있는 문자로만 구성
        
        for(int i = 0; i < s1.length; i++) {
            int num = Integer.parseInt(s1[i]);
            int index = i + 1;                              //첫번째 문자열은 공백이기에 제외
            while(!s2[index].isBlank()) {
                if(s2[index].matches("S(.*)"))
                    stack.push(num);
                else if(s2[index].matches("D(.*)")) {
                    num *= num;
                    stack.push(num);
                }
                else if(s2[index].matches("T(.*)")) {
                    num *= num * num;
                    stack.push(num);
                }
                else if(s2[index].matches("#(.*)")) {
                    stack.push(stack.pop() * -1);
                }
                else {                                      //스타상(*)일 때
                    if(stack.size() >= 2) {                 //이미 두 개 이상의 점수를 획득했을 때
                        int temp1 = stack.pop() * 2;
                        int temp2 = stack.pop() * 2;
                        stack.push(temp2);
                        stack.push(temp1);
                    }
                    else                                    //획득한 점수가 1개일 때
                        stack.push(stack.pop() * 2);
                }
                s2[index] = s2[index].substring(1);         //첫 번째 문자 제거
            }
        }
        while(!stack.isEmpty())                             //계산 결과 전부 더하기
            answer += stack.pop();
        return answer;
    }
}

2. 설명

int answer = 0;
Stack <Integer> stack = new Stack<>();
String[] s1 = dartResult.split("[^0-9]+");          //문자 사이에 있는 숫자로만 구성
String[] s2 = dartResult.split("[0-9]+");           //숫자 사이에 있는 문자로만 구성

이 문제는 스택을 이용한다면 조금 쉽게 해결할 수 있습니다. split() 메서드는 matches() 메서드와 마찬가지로 정규식으로 처리가 가능하기에 s1은 문자들을 기준으로 숫자들을 추출하고 s2는 숫자들을 기준으로 문자들을 추출합니다.

for(int i = 0; i < s1.length; i++) {
    int num = Integer.parseInt(s1[i]);
    int index = i + 1;                              //첫번째 문자열은 공백이기에 제외

s2의 경우 숫자로 구분하여서 첫 번째 숫자를 기준으로 좌우로 추출되어 공백이 추가로 추출되기에 제일 처음에는 공백이 추출되므로 공백을 제외하기 위해서 i + 1을 index에 저장하여 index는 s2의 인덱스 값입니다. 문자열로 추출했기에 활용할 문자열의 길이는 s1와 s2가 동일합니다.

while(!s2[index].isBlank()) {
    if(s2[index].matches("S(.*)"))
        stack.push(num);
    else if(s2[index].matches("D(.*)")) {
        num *= num;
        stack.push(num);
    }
    else if(s2[index].matches("T(.*)")) {
        num *= num * num;
        stack.push(num);
    }
    else if(s2[index].matches("#(.*)")) {
        stack.push(stack.pop() * -1);
    }
    else {                                      //스타상(*)일 때
        if(stack.size() >= 2) {                 //이미 두 개 이상의 점수를 획득했을 때
            int temp1 = stack.pop() * 2;
            int temp2 = stack.pop() * 2;
            stack.push(temp2);
            stack.push(temp1);
        }
        else                                    //획득한 점수가 1개일 때
            stack.push(stack.pop() * 2);
    }
    s2[index] = s2[index].substring(1);         //첫 번째 문자 제거
}

문자가 S, D, T가 나오면 즉시 Stack에 값을 push하여 스타상(*)과 아차상(#)일 때는 Stack의 값을 pop한 뒤 처리하여 다시 push해줍니다. 문자에 적절한 처리가 되었다면 s2의 인덱스의 문자열에서 첫 번째 문자를 없애주며 문자열이 없어질 때까지 반복해 줍니다.

while(!stack.isEmpty())                             //계산 결과 전부 더하기
    answer += stack.pop();

모든 과정이 마무리되면 Stack에 저장된 값들을 전부 더해주면 문제는 해결됩니다.

3. 정리

  1. split() 메서드와 정규식을 활용하여 문자와 숫자를 구분
  2. Stack을 활용하여 계산 결과를 임시로 저장
  3. 두 글자 이상의 문자열에서 정규식 주의(예: s2.matches("S")은 "S"에서는 true, "S*"에서 false로 반환하기에 s2.matches("S(.*)")은 "S*"와 "S" 모두 true 반환)
출처: 프로그래머스 코딩 테스트 연습, 
https://school.programmers.co.kr/learn/challenges