유효한 연산식 문자열 s
숫자, 공백, +, -, (, )로 이루어져 있음
연산식을 계산하여 결과값 반환
/**
* @param {string} s
* @return {number}
*/
var calculate = function(s) {
let res = 0;
let num = 0;
let sign = 1;
let stack = [1];
for (let i = 0; i < s.length; i++) {
const temp = s[i];
if (isNaN(parseInt(temp)) === false)
num = num * 10 + parseInt(temp);
else if (temp === '(')
stack.push(sign);
else if (temp === ')')
stack.pop();
else if (temp === '+' || temp === '-') {
res += sign * num;
sign = (temp === '+' ? 1 : -1) * stack[stack.length - 1];
num = 0;
}
}
return res + sign * num;
};
문자열을 돌면서 각 문자의 형태에 따라 처리
숫자
: 두 자리 이상의 수일 수 있으므로 연산 기호를 만나기 전까지는 자릿수를 늘려가며 (*10) num에 계속 저장
(
: 괄호 시작을 만나면 그 앞의 부호에 따라 괄호 내의 부호가 변경될 수 있으므로 스택에 저장
)
: 괄호를 닫고 나면 괄호 시작 전의 부호를 기억하지 않아도 되므로 스택에서 삭제
+, -
: 숫자가 끝났으므로 숫자 앞의 부호에 따라 결과값에 더하거나 뺀 후 다음 숫자를 위해 현재의 부호를 sign에 저장 및 num 초기화
다만 괄호 내의 연산 기호일 수도 있으므로 스택의 마지막 값과 곱한 결과를 사용 (괄호 내가 아닐 경우 스택에 기본적으로 담겨있는 것이 1이기 때문에 곱해도 변하지 않음)
마지막은 숫자 혹은 닫는 괄호로 끝나므로 남아있는 수를 결과값에 연산해주고 반환
Accepted
Runtime 64ms (Beats 75.36%)
Memory 52.60MB (Beats 63.39%)
이번에는 온전히 나의 힘으로 풀어내지 못했다. 괄호 때문에 많이 헤맸는데, 먼저 후위 연산식으로 바꿔서 그걸 다시 계산하려고 하다가 너무 많은 조건이 붙는 걸 보고 이건 절대 아닌 것 같다고 판단했다. 그래서 솔루션을 찾아보다가 너무 간단한 코드를 발견해버렸다. 사실 처음에 괄호를 풀어서 기호, 숫자, 기호, 숫자가 반복되게 만들어야하지 않을까 라는 생각을 하긴 했었는데 좀 더 노력해볼 걸 그랬다. 참고한 코드를 좀 더 설명하자면 기본적으로 +3
-4
+5
와 같이 기호가 앞, 숫자가 뒤인 형태로 끊어가면서 계산한다. 0에서부터 시작하여 기호와 숫자를 기억해두었다가 다음 기호를 만나면 그 둘을 곱한 값을 더한다. 그리고 포인트는 괄호를 풀기 위해서 괄호 바로 앞 기호를 스택에 넣어둔 뒤 닫히기 전 만난 기호는 그와 함께 곱한다. 다 이해하고 나니 정말 간단하다는 생각이 든다... 포기하지 말고 좀 더 머리를 굴려보자.