- 총 3번 다트를 던지고, 보너스(S,D,T)나 옵션(*,#)에 따라서 이전 점수를 다시 조작해야 하기 때문에 각 점수를 따로 저장해야 함.
- 문자열을 하나씩 읽어서 점수, 보너스, 옵션을 구분하고 각 케이스에 맞게 점수를 반영.
- 점수는 0-10점으로, 문자열로 10이 주어지기 때문에, 점수가 1인지 10인지 구분해야 함.
- 먼저 점수가 몇 점인지 확인 후 스택에 저장.
1-1. 이때 점수가 1로 시작하는 경우와 그렇지 않은 경우로 나눠서 처리.
1-2. 1로 시작하는 경우는 1점이거나 10점인 경우가 있고, 나머지는 0, 2-9점인 경우.- 보너스에 따라 스택에 저장된 점수를 다시 꺼내서 계산 후 저장.
- 옵션에 따라 점수 다시 계산 후 스택에 저장.
3-1. 옵션이 * 인 경우 : 첫 번째 기회인지, 아니면 두 번째, 세 번째 기회인지에 따라 다르게 처리해야 함. (두 번째, 세 번째 기회일 경우, 현재 점수와 바로 이전의 점수 모두 2배로 계산.)
3-2. 옵션이 # 인 경우 : 현재 기회에서 얻은 점수만 -1 곱해서 스택에 저장.- 1-3번이 각 기회마다 일어남.
#include<iostream>
#include <string>
#include <vector>
#include<cmath> //pow()
#include <stack>
using namespace std;
int answer = 0;
int solution(string dartResult) {
int score1, score2 =0;
stack<int> sc;
for(int i=0; i<dartResult.size(); i++){
//1.다트의 점수가 1인지 10인지 확인하기
if(dartResult[i] == '1'){
sc.push(dartResult[i] - '0'); //1점인 경우
if(dartResult[i+1] == '0'){ //다음 인덱스가 0이면 점수는 10
sc.pop(); //넣어둔 1점 빼기
sc.push(10); //스택에 10점 넣기
i++; //점수가 10일경우 i를 증가 시켜줘야 다음 인덱스 (D T S)로 이동가능
}
//2.점수 값 계산하기
if(dartResult[i+1] == 'D'){ //점수가 D일 경우 이전 점수의 2제곱
score1 = sc.top();
sc.pop();
sc.push(pow(score1, 2)); //2제곱 한 값 스택에 넣기
}else
if(dartResult[i+1] == 'T'){ //점수가 T일 경우 이전 점수의 3제곱
score1 = sc.top();
sc.pop();
sc.push(pow(score1, 3)); //3제곱 한 값 스택에 넣기
}
}else{
//0~9점인 경우
sc.push(dartResult[i] - '0');
if(dartResult[i+1] == 'D'){ //점수가 D일 경우 이전 점수의 2제곱
score1 = sc.top();
sc.pop();
sc.push(pow(score1, 2)); //2제곱 한 값 스택에 넣기
}else if(dartResult[i+1] == 'T'){ //점수가 T일 경우 이전 점수의 3제곱
score1 = sc.top();
sc.pop();
sc.push(pow(score1, 3)); //3제곱 한 값 스택에 넣기
}
}//여기까지는 옵션 빼고 점수 계산 된 상태
i++; //다음 인덱스(S,D,T)로 이동
//3.옵션이 있다면 처리해야 함.
if(dartResult[i+1] == '*' || dartResult[i+1] == '#'){
//옵션이 스타상(*)이라면
if(dartResult[i+1]=='*'){
//스택에 점수가 하나만 있을때
if(sc.size()==1){
score1 = sc.top();
sc.pop();
sc.push(score1*2);
}else{
//스택에 점수가 하나 이상인 경우는 현재 점수와 이전 점수 계산해야함
score1 = sc.top(); //현재 점수
sc.pop();
score1 *=2;
score2 = sc.top(); //바로 전 점수
score2 *=2;
sc.pop();
sc.push(score2);
sc.push(score1);
}
}else{
//옵션이 #(아차상)인 경우 현재 점수 마이너스 처리
score1 = sc.top();
sc.pop();
sc.push(-1*score1);
}
i++; //다음 인덱스(옵션)으로 인덱스 이동
}
}
while(!sc.empty()){
answer += sc.top();
sc.pop();
}
return answer;
}
👉 제곱 계산용 함수
1. #include <cmath> 헤더 파일 포함 시키기
2. pow(숫자, 지수);
ex) 10의 세제곱 계산 : pow(10, 3);
👉C++에서의 문자열
C++에는 문자열을 나타내는 두 가지 방법이 있음.
1. char형 배열 : 마지막에 자동으로 null
- 문자열의 크기에 항상 신경써야 함. 배열의 크기가 충분하지 않을 경우 error.
- string 클래스 사용.
- 문자열 저장과 처리에 필요한 변수와 함수들의 정의되어 있음.
- 문자열의 크기를 신경쓰지 않고 사용 가능.
#include <string>
#include <sstream>
#include <cmath>
using namespace std;
int solution(string dartResult) {
stringstream ss(dartResult);
int sum[3] = { 0, 0, 0 };
int options[3] = { 1, 1, 1 };
for (int i = 0; i < 3; i++) {
int score;
char bonus;
char option;
ss >> score;
bonus = ss.get();
option = ss.get();
if (option != '*' && option != '#') {
ss.unget();
}
switch (bonus) {
case 'S':
sum[i] += pow(score, 1);
break;
case 'D':
sum[i] += pow(score, 2);
break;
case 'T':
sum[i] += pow(score, 3);
break;
default:
break;
}
switch (option) {
case '*':
if (i > 0 && options[i - 1]) options[i - 1] *= 2;
options[i] *= 2;
break;
case '#':
options[i] = -options[i];
break;
default:
break;
}
}
return sum[0] * options[0] + sum[1] * options[1] + sum[2] * options[2];
}
하나의 문자열로 주어진 3개의 케이스를 각각 어떻게 분리할지 생각하는 것이 오래 걸렸다.
특히 숫자를 기준으로 나누려 했더니 0-9점까지가 아니고 10점까지라 10점인 걸 어떻게 확인할지 고민함. 다른 풀이를 보면 보너스 (S,D,T)를 기준으로 앞, 뒤로 나눠서 계산하기도 하던데 그 방법으로도 풀어볼 예정. 문자열 처리는 계산이나 구분, 분리에서 까다로운 경우가 많아서 다양한 케이스, 함수를 익히는 것이 중요할 듯!