[Programmers] [1차] 다트 게임

lkdcode·2023년 10월 19일

Algorithm

목록 보기
45/47
post-thumbnail

[1차] 다트 게임


문제 분석

자세한 내용은 위의 링크를 참조.

  1. 문자열 dartResult 가 주어진다.
  2. S, D, T 중 1개씩 총 3개를 포함한다.
    • S : 점수의 1승
    • D : 점수의 2승
    • T : 점수의 3승
  3. 0~10 까지 점수 중 1개씩 총 3개를 포함한다.
  4. *, # 중 1개씩 총 3개를 랜덤으로 포함한다.
    • * : 해당 점수 2배, 이전 점수 2배
    • # : 점수를 음수로 변경
  5. 얻은 점수를 리턴하라.

ex)
dartResult = "1S2D*3T"
1. 첫 번째 점수 : 점수 : 1, 보너스 : S, 옵션 : 없음
2. 두 번째 점수 : 점수 : 2, 보너스 : D, 옵션 : *
3. 세 번째 점수 : 점수 : 3, 보너스 : T, 옵션 : 없음

dartResult = "1S*2T*3S"
1. 첫 번째 점수 : 점수 : 1, 보너스 : S, 옵션 :
2. 두 번째 점수 : 점수 : 2, 보너스 : T, 옵션 :

3. 세 번째 점수 : 점수 : 3, 보너스 : S, 옵션 : 없음

입출력 예제


풀이 과정

코딩 테스트에서 흔히 볼 수 있는 첫 번째 문제 유형이다.
보통 첫 번째 유형으로 문자열 가공 문제가 많이 제출되는 것 같다.
문자열 가공 로직이 중요하다.
어떻게 문자열을 요리할 것인가? 그것이 나의 접근 방식이다.

🎯 문자열 가공

해당 문제는 항상 등장하는 보너스점수 를 기준으로 문자열을 나눌 수 있을 것 같다.
옵션 은 등장할 수도, 안 할 수도 있다. 그래서 옵션 을 기준으로는 나눌 수 없다.

보너스점수 중 어느 문자를 기준으로 문자열을 나눌 것인가?

점수length1 아니면 2 다. (0점 ~ 10점)
보너스 는 항상 S, D, T 중 하나일 것이다.

length 기준이 S, D, T 보다 번거롭다.
보너스 를 기준으로 문자열을 나눈 뒤, 점수 를 계산하고 옵션 을 계산한다.

문자열을 담을 배열을 선언한다.
총 3번의 기회이므로 사이즈는 3
점수, 보너스, 옵션 총 3가지의 배열 선언

        int[] point = new int[3]; // 점수를 담을 배열
        String[] bonus = new String[3]; // 보너스를 담을 배열
        String[] option = new String[3]; // 옵션을 담을 배열

🎯 S, D, T 로 문자열을 나누기

주어질 dartResult 이 어떤 문자열(값)을 가지고 있을지 모르지만,
점수, 보너스 는 확실히 있다.
그 중에서도 보너스(S, D, T) 를 기준으로 문자열을 자르자.

        int index = 0; // 배열 인덱스
        String inputPoint = ""; // 추가할 점수

        for (int i = 0; i < dartResult.length(); i++) {
            char check = dartResult.charAt(i); // 하나씩 잘라서,

            if (check == 'S'
                    || check == 'D'
                    || check == 'T') { // S, D, T 중 하나라면
                point[index] = Integer.parseInt(inputPoint.replaceAll("[#*]", "")); // point에 점수 추가!
                bonus[index++] = String.valueOf(check); // 보너스에 S, D, T 중 하나 추가! , 배열 인덱스 증가
                inputPoint = ""; // 추가할 점수 문자열 초기화
                continue; // 아래 로직 스킵
            }

            inputPoint += check; // S, D, T 가 아니라면 점수다.
        }

charAt() 으로 잘라낸 문자가 만약 S, D, T 중 하나라면 각 배열에 추가해준다.
그게 아니라면 String inputPoint 에 더해주게 되는데
S, D, T 가 아니라면 점수거나 옵션일테고 inputPoint 에 값이 할당된다.

예시로 "1S2D*3T" 가 주어진다면,
처음 S 가 등장하는 시점에 String inputPoint"1" 이 될 것이다.

다시 if 문 로직으로 돌아가서,
점수만 체크하기 위해 inputPoint.replaceAll() 로 옵션들을 제거해준뒤
int point[] 배열에 추가해준다.

String bonus[] 배열도 마찬가지로 추가해준다. (.charAt() 자체가 S, D, T 중 하나)
String inputPoint 의 문자열을 초기화해준뒤 continue 를 실행해 다음 로직을 스킵해준다.


🎯 가지고 있는 배열로 먼저 계산

점수와 보너스를 얻었기 때문에 먼저 계산해보자.
첫 번째 점수 = point[0] * bonus[0]
두 번째 점수 = point[1] * bonus[1]
세 번째 점수 = point[2] * bonus[2]

만약,
bonus[] == 'S' 라면 point[] * 1 (point[]의 1승)
bonus[] == 'D' 라면 point[] * point[] (point[]의 2승)
bonus[] == 'T' 라면 point[] * point[] * point[] (point[]의 3승)

        for (int i = 0; i < point.length; i++) {
            if (bonus[i].equals("D")) {
                point[i] = point[i] * point[i];
            }
            if (bonus[i].equals("T")) {
                point[i] = point[i] * point[i] * point[i];
            }
        }

S 1승은 할 필요 없다.
D, T 만 계산해주자.


🎯 옵션을 체크해보자

보너스는 항상 등장, length1 이다. (S, D, T)
점수도 항상 등장, length 1 or 2 다. (0 ~ 10)
옵션은 등장할 수도, 안 할수도..

1S1D1T 가 주어질 수도, 10S*10D*10T* 가 주어질 수도 있다.
특정 위치에 고정적으로 옵션이 등장하지 않으므로
문자열의 최소 렝스와 최대 렝스 를 따지면 계산이 조금 번거로워진다.

첫 번째 옵션과 마지막 옵션을 기준으로 체크하고 그 외에 위치는 두 번째 옵션으로 본다.

        for (int i = 0; i < dartResult.length(); i++) {
            char check = dartResult.charAt(i); // 하나씩 문자로 잘라서

            if (check == '*' || check == '#') { // 옵션이라면,
                if (i < 3) option[0] = String.valueOf(check); // 첫번째 옵션 등장 규칙
                else if (i == dartResult.length() - 1) option[2] = String.valueOf(check); // 마지막 옵션 등장 규칙
                else option[1] = String.valueOf(check); // 그 외 등장은 항상 두 번째 옵션
            }
        }

옵션이 아예 없는 최소 length 든,
10점이면서 옵션 이 전부 등장하는 최대 length
(ex.1S1D1T, 10S*10D*10T*)

첫 번째 옵션 등장 위치는 항상 3미만이다.
세 번째 옵션 등장 위치는 항상 마지막 렝스다.
두 번째 옵션 등장 위치는 위의 둘이 아니면 맞다.


🎯 옵션을 계산하자

옵션 이 비어있다면 스킵,
그게 아니라면 주어진 문제에 따라 계산해주자.
# 은 점수를 음수로 바꿔주는 것.
* 은 해당 점수를 2배로, 그 앞의 점수도 2배로.

        for (int i = 0; i < option.length; i++) {
            if (option[i] == null) continue;

            if (option[i].equals("#")) {
                point[i] -= point[i] * 2;
            }

            if (option[i].equals("*")) {
                point[i] += point[i];
                int preIndex = i - 1;

                if (preIndex >= 0) point[preIndex] += point[preIndex];
            }
        }

나의 생각

문자열 가공 문제는 항상 여러 로직들을 순차적으로 실행시키는 문제들이 많은 것 같다.
얼만큼 자료 구조에 잘 담고 있으며 너가 생각하는 로직이 얼마나 단순하고 어떤 효율이 보여주는가? 를 묻는 느낌이 강하다.
문자열 가공 문제는 꼬여있는 문제들을 하나씩 천천히 풀다보면 정답을 얻을 수 있는 것 같다.


코드

import java.util.*;

class Solution {
    public int solution(String dartResult) {
        int answer = 0;

        int[] point = new int[3];
        String[] bonus = new String[3];
        String[] option = new String[3];

        int index = 0;
        String inputPoint = "";

        for (int i = 0; i < dartResult.length(); i++) {
            char check = dartResult.charAt(i);

            if (check == 'S'
                    || check == 'D'
                    || check == 'T') {
                point[index] = Integer.parseInt(inputPoint.replaceAll("[#*]", ""));
                bonus[index++] = String.valueOf(check);
                inputPoint = "";
                continue;
            }

            inputPoint += check;
        }

        for (int i = 0; i < point.length; i++) {
            if (bonus[i].equals("D")) {
                point[i] = point[i] * point[i];
            }
            if (bonus[i].equals("T")) {
                point[i] = point[i] * point[i] * point[i];
            }
        }

        for (int i = 0; i < dartResult.length(); i++) {
            char check = dartResult.charAt(i);

            if (check == '*' || check == '#') {
                if (i < 3) option[0] = String.valueOf(check);
                else if (i == dartResult.length() - 1) option[2] = String.valueOf(check);
                else option[1] = String.valueOf(check);
            }
        }

        ///////////////////////////////////////


        // for (int i : point) {
        //     System.out.print(i + " ");
        // }

        ///////////////////////////////////////

        // for (String s : option) {
        //     System.out.println(s);
        // }

        ///////////////////////////////////////

        for (int i = 0; i < option.length; i++) {
            if (option[i] == null) continue;

            if (option[i].equals("#")) {
                point[i] -= point[i] * 2;
            }

            if (option[i].equals("*")) {
                point[i] += point[i];
                int preIndex = i - 1;

                if (preIndex >= 0) point[preIndex] += point[preIndex];
            }
        }

        ///////////////////////////////////////

        // System.out.println();
        // for (int i : point) {
        //     System.out.print(i + " ");
        // }

        ///////////////////////////////////////

        return Arrays.stream(point).sum();
    }
}

profile
되면 한다

0개의 댓글