S-표현식(S-expression)이란?
문자열 s가 S-표현식(S-expression)으로 주어졌을 때, 이를 평가하여 그 결과를 정수로 반환하는 프로그램을 작성해 보겠습니다.
S-표현식은 하나의 숫자이거나, 괄호로 감싸진 재귀적인 표현식입니다. 예를 들어 (+ (- 3 2) (* 3 3))은 일반적인 수학 표기법으로 (3 - 2) + (3 * 3)과 같으며, 그 결과는 10이 됩니다. 사용할 수 있는 유효한 연산자는 +, -, *, / 네 가지입니다.
예를 들어 입력이 s = "(- (+ 3 2) 2)"라면, 이는 ((3 + 2) - 2)와 같으므로 출력 결과는 3이 됩니다.
해결 접근 방법
이 문제는 스택(stack) 자료구조를 활용하면 깔끔하게 해결할 수 있습니다. 핵심 아이디어는 다음과 같습니다.
- 새로운 스택을 생성합니다.
- 문자열에서 여는 괄호
(와 닫는 괄호)를 모두 제거합니다. - 공백을 기준으로 문자열을 분리하여 리스트로 만듭니다.
- 리스트를 뒤에서부터(역순으로) 순회합니다. S-표현식은 연산자가 피연산자보다 앞에 오는 전위 표기법이므로, 역순으로 읽으면 일반적인 후위 표기식처럼 처리할 수 있기 때문입니다.
- 순회 중 각 요소
i에 대해 다음을 수행합니다.- 길이가 1보다 큰 경우: 음수일 가능성이 있습니다. 첫 글자가
-인지 확인한 후 정수로 변환하여 스택에 push합니다. - 숫자인 경우: 정수로 변환하여 스택에 push합니다.
- 연산자인 경우: 스택에서 두 개의 값을 pop하고, 해당 연산을 수행한 뒤 결과를 다시 스택에 push합니다.
- 길이가 1보다 큰 경우: 음수일 가능성이 있습니다. 첫 글자가
- 모든 순회가 끝나면 스택의 최상단 값을 pop하여 반환합니다. 이것이 최종 계산 결과입니다.
Python 구현 코드
아래 코드를 통해 실제 구현을 확인해 보겠습니다.
class Solution:
def solve(self, s):
stack = list()
s = s.replace("(", "")
s = s.replace(")", "")
a = s.split()
for i in a[::-1]:
if len(i) > 1:
if i[0] == "-":
stack.append(int(i))
continue
else:
stack.append(int(i))
elif i.isdigit():
stack.append(int(i))
else:
if len(stack) >= 2:
num1 = stack.pop()
num2 = stack.pop()
if i == "+":
stack.append(int(num1 + num2))
elif i == "-":
stack.append(int(num1 - num2))
elif i == "*":
stack.append(int(num1 * num2))
else:
stack.append(int(num1 / num2))
return stack.pop()
ob = Solution()
s = "(- (+ 3 2) 2)"
print(ob.solve(s))입력 예시
s = "(- (+ 3 2) 2)"
출력 결과
3
코드 설명 및 시간 복잡도
이 알고리즘의 동작 과정을 단계별로 살펴보면 다음과 같습니다.
- 괄호 제거 후
s는- + 3 2 2가 되고, 공백으로 분리하면["-", "+", "3", "2", "2"]리스트가 생성됩니다. - 역순으로 순회하면
2,2,3이 차례로 스택에 쌓입니다. +를 만나면3과2를 pop하여 더한 값5를 스택에 push합니다.-를 만나면5와2를 pop하여 뺀 값3을 스택에 push합니다.- 최종적으로 스택에는
3만 남고, 이것이 반환됩니다.
시간 복잡도는 O(n), 공간 복잡도 역시 O(n)입니다. 여기서 n은 입력 문자열의 길이입니다.
주의할 점은 나눗셈(/)의 경우 Python 3에서 실수 나눗셈을 수행하므로, 정수 결과가 필요하다면 몫 연산(//)을 사용하는 것이 안전할 수 있다는 것입니다. 또한 이 구현은 잘못된 형식의 입력에 대한 예외 처리는 포함하지 않으므로, 실제 서비스에 적용할 때는 유효성 검사 로직을 추가하는 것이 좋습니다.