※ 본 사진과 해당 게시글 내용의 문제 모두 프로그래머스[Programmers]사이트에 발췌해왔습니다.
프로그래머스를 사정이 있어 잠깐 쉬고
최근에는
알고리즘 스터디도 진행하고 있지만
문제를 백준에서 풀다보니
이 문제는 정말 오랜만에 프로그래머스를 방문해서 맞닥뜨린 문제였는데
아뿔사...
그래도 Lv.1 문제는 이제 풀기 쉽겠지 라는 생각하던 찰나
나의 근거없는 자신감을 다시 밟아 다져준(?) 문제인 것 같다..
(무슨 1시간을 넘게 머리 싸매서 풀어... )
아직 멀었다... 아직 내가 풀었던 건 아무것도 아니였다...
아직 부족하다는 현실을 깨닫고 앞으로 더 많이 풀어야 겠다는 다짐을 하며 시작해보겠다..
다트 게임은 다트판에 다트를 세 차례 던져 그 점수의 합계로 실력을 겨루는 게임이다.
다트 게임의 점수 계산 로직은 아래와 같다.
다트 게임은 총 3번의 기회로 구성된다.
각 기회마다 얻을 수 있는 점수는
0점에서 10점까지이다.
점수와 함께 Single(S), Double(D), Triple(T) 영역이 존재하고
각 영역 당첨 시
점수에서 1제곱, 2제곱, 3제곱 (점수1 , 점수2 , 점수3 )으로 계산된다.
옵션으로 스타상(*) , 아차상(#)이 존재하며
스타상(*) 당첨 시
해당 점수와 바로 전에 얻은 점수를 각 2배로 만든다.
아차상(#) 당첨 시
해당 점수는 마이너스된다.
스타상(*)은 첫 번째 기회에서도 나올 수 있다.
이 경우
첫 번째 스타상(*)의 점수만 2배가 된다. (예제 4번 참고)
스타상(*)의 효과는 다른 스타상(*)의 효과와 중첩될 수 있다.
이 경우
중첩된 스타상(*) 점수는 4배가 된다. (예제 4번 참고)
스타상(*)의 효과는 아차상(#)의 효과와 중첩될 수 있다.
이 경우
중첩된 아차상(#)의 점수는 -2배가 된다. (예제 5번 참고)
Single(S), Double(D), Triple(T)은
점수마다 하나씩 존재한다.
스타상(*), 아차상(#)은
점수마다 둘 중 하나만 존재할 수 있으며, 존재하지 않을 수도 있다.
0~10의 정수와 문자 S, D, T, *, #로 구성된 문자열이 입력될 시 총점수를 반환하는 함수를 작성하라.
<입력 형식>
"점수|보너스|[옵션]"으로 이루어진 문자열 3세트.
예) 1S2D*3T
점수는 0에서 10 사이의 정수이다.
보너스는 S, D, T 중 하나이다.
옵선은 *이나 # 중 하나이며, 없을 수도 있다.
출력 형식
3번의 기회에서 얻은 점수 합계에 해당하는 정수값을 출력한다.
예) 37
<입출력 예제>
예제 dartResult answer 설명
1 1S2D*3T 37 11 * 2 + 22 * 2 + 33
2 1D2S#10S 9 12 + 21 * (-1) + 101
3 1D2S0T 3 12 + 21 + 03
4 1S*2T*3S 23 11 * 2 * 2 + 23 * 2 + 31
5 1D#2S*3S 5 12 * (-1) * 2 + 21 * 2 + 31
6 1T2D3D# -4 13 + 22 + 32 * (-1)
7 1D2S3T* 59 12 + 21 * 2 + 33 * 2
def solution(dartResult):
answer = [] # 더할 각 단계 계산 점수값을 담을 리스트
num = '' # 10이라는 두자릿수 값의 경우까지 가능한 " 문자열로의 누적합 " 활용 _ 초기화 또한 용이한 장점
for i in dartResult :
if i.isdigit() : # 숫자일 경우
num += i # 점수를 입력
elif i in ['S', 'D', 'T'] : # S, D, T의 경우
if i == 'S' :
answer.append(int(num)) # 각 단계의 결과 점수
num = '' # 초기화
elif i == 'D' :
answer.append(int(num)**2) # 각 단계의 결과 점수
num = '' # 초기화
else :
answer.append(int(num)**3) # 각 단계의 결과 점수
num = '' # 초기화
elif i in ["*", "#"] : # 옵션의 경우
if i == "*" :
if len(answer) == 1 :
answer[-1] = answer[-1]*2 # 수정
# answer에서 가장 최근에 들어갔던 값에 대해 수행되게끔
else : # 스타상
# 해당 점수와 바로 전에 얻은 점수를 각 2배
answer[-1] = answer[-1]*2
answer[-2] = answer[-2]*2
else : # 아차상
answer[-1] = answer[-1]*-1
return sum(answer)
사실 들어가기 앞서 말했듯이
해당 문제를 푸는데 시간이 적지않게 소요되었는데
아무래도 다른 분들이 푼 방법들도 살펴보았다.
숫자와 문자가 번갈아 나오며
나올 때마다 초기화 되어야 하는 경우가 있어
이 두 가지를를 어떻게 유동적으로 붙였다 삭제를 할 수 있을까 골치 아팠었다.
(필자는 정규표현식 & Dict 자료구조 활용 이나 타입 상관없이 리스트를 활용해볼까 를 고민해보았지만 아직 성공하지 못해 더 시도해봐야 하긴 하다..)
그러던 중
삭제에도 용이할 뿐더러
누적합도 가능한 방법이 있었다.
바로 문자열 이였다.
(1)
import re
def solution(dartResult):
# { Key : Value } 딕셔너리 활용
bonus = {'S' : 1, 'D' : 2, 'T' : 3} # SDT의 경우에 대해 할당되는 계산 값들을 짝지어줌.
option = {'' : 1, '*' : 2, '#' : -1} # 아무 상도 없으면 값 그대로 유지 : 1로 연산에 활용
# " (digit)([S나 D나 T가 나온 경우])([스타상이나 아차상의 경우 : 있어도그만 없어도 그만]) " <- 이 구성를 단위로
# 전체 중에 위 구조의 덩어리들을 1차적으로 분리하고
# 중괄호를 기준으로 각자 2차적으로 분리한다.
# 스타상(*)이나 아차상(#)이 없더라도 ()로 분리되었기때문에 '' 비어있는 값도 하나의 값으로 분리됨.
p = re.compile('(\d+)([SDT])([*#]?)') # 정규표현식을 통해 S, D, T가 쓰인 경우로 나누어줌
dart = p.findall(dartResult) # 위 구조에 해당하는 부분을 찾아냄 (분리되는 과정)
for i in range(len(dart)): # 찾아낸 것들을 하나씩 계산
if dart[i][2] == '*' and i > 0: # 첫번째 덩어리의 끝 부분
dart[i-1] *= 2
# 처음에 설정한 dict에 value들을 가져와서 연산하기
dart[i] = int(dart[i][0]) ** bonus[dart[i][1]] * option[dart[i][2]]
answer = sum(dart)
return answer
필자가 도전하던 정규 표현식과 Dict 형식의 " Key-Value " 성질을 사용한 경우이다.
아직 정규표현식을 정확하게 활용하기 위해선
더 공부가 필요한 것 같다.
조만간 정규표현식도 한 번 알아봐야겠다..