1918 후위 표기식
1918 후위 표기식 (c++)
문제
https://www.acmicpc.net/problem/1918
접근 방식
스택, 자료구조
- 중위 표기식의 수식을 후위 표기식으로 바꾼다.
- 문자는 문자열에 바로 추가
- 연산자는 스택의 탑 보다 우선순위가 높으면 추가
- 높지 않으면 스택을 위에서부터 우선순위가 나보다 높거나 같은 것들을 문자열에 추가
- 후 스택에 현재 연사자를 추가
- 그랬더니 괄호가 문제였다.
- 처음엔 재귀형식으로 풀려고 했다.
- 괄호가 나오면 해당 괄호와 짝이 되는 닫는 괄호 위치를 파악
- 여는 괄호부터 닫는 괄호까지를 다시 함수에 넣어 재귀 진행
- 시간초과가 나왔다.
- 처음엔 재귀형식으로 풀려고 했다.
- 시간초과를 어떻게하면 해결할 수 있을까 (어떻게 재귀 없이 한번의 연산으로 다 처리할 수 있을까)
- 지금 골자가 우선순위를 보고 스택에 바로 넣을지 한번 뱉어내고 넣을지를 정하기 때문에 괄호로 우선 순위를 조절할 수 있지 않을까 생각
- 연산자는 +, -, *, / 총 4개이므로 각각을 번호로 0,1,2,3 을 매기고
- 여는 괄호가 나오면 score+=10, 닫는 괄호가 나오면 score-=10
- 얼추 굴러가긴 하는데, 정확히 원하는 계산값이 나오지 않았다, 뱉을지 말지 여부를 결정하는 조건이 문제였다.
- score가 높다면 (더 안쪽괄호의 연산자라면) 무조건 스택에 삽입
- score가 같다면 (같은 괄호에 있는 연산자라면)
- /2를 해준다 (덧뺄셈, 곱나눗셈을 구분지어줌)
- 스택의 탑이 현재 연산자보다 높거나 같다면 뱉어준다.
(여기서 문제가 있었다. 높기만 하면 되는 줄 알았는데, 같은 우선순위여도 한번 뱉고 넣어야했다.) - 그 후 스택에 삽입
- 마지막으로 스택에 남아있는 연산자들도 문자열에 추가해준다.
문제 풀이
#pragma GCC optimize("Ofast")
#include <iostream>
#include <string>
#include <stack>
#include <map>
using namespace std;
inline bool Check(int A, int B) { return (A / 10 > B > 10 || ((A / 10 == B / 10) && (A % 10 / 2 >= B % 10 / 2))); }
string str;
map<char, int> m = { {'+', 0}, {'-', 1}, {'*', 2}, {'/', 3} };
map<int, char> m2 = { {0, '+'}, {1, '-'}, {2, '*'}, {3, '/'} };
string Solve()
{
string result = "";
int score = 0;
stack<int> oStack;
for (int i = 0; i < str.size(); ++i)
{
if (str[i] >= 'A' && str[i] <= 'Z')
{
result += str[i];
}
else if (str[i] == '(') score += 10;
else if (str[i] == ')') score -= 10;
else
{
if (!oStack.empty())
{
if (Check(oStack.top(), score + m[str[i]]))
{
while (!oStack.empty() && Check(oStack.top(), score + m[str[i]]))
{
int now = oStack.top(); oStack.pop();
result += m2[now % 10];
}
}
}
oStack.push(m[str[i]] + score);
}
}
while (!oStack.empty())
{
int now = oStack.top(); oStack.pop();
result += m2[(now % 10)];
}
return result;
}
int main()
{
cin >> str;
str = Solve();
cout << str << '\n';
return 0;
}
다시 생각해 볼 점
- 이것도 거의 1시간 반을 잡아먹은 것 같다.
- 1시간 넘어갈즘 문제 분류를 봤지만 별다른 힌트가 될만한 건 없었다.
- 그래도 일단 괄호를 재귀로 해결해보려고 하고, 시간초과가 났을 때 더 시간효율이 높은 방법으로 괄호에 점수를 부여해보면 어떨까 생각했던 점은 잘한 것 같다.
- 이런 전위 중위 후위 표기 (혹은 순회)는 스택과 관련이 깊다는 걸 염두해둬야겠다.