題目描述
給你一個字串表示式 s ,請你實現一個基本計算器來計算並返回它的值。
注意:不允許使用任何將字串作為數學表示式計算的內建函式,比如 eval() 。
-
示例 1:
輸入:s = "1 + 1"
輸出:2 -
示例 2:
輸入:s = " 2-1 + 2 "
輸出:3 -
示例 3:
輸入:s = "(1+(4+5+2)-3)+(6+8)"
輸出:23 -
提示:
1 <= s.length <= 3 * 105
s 由數字、'+'、'-'、'('、')'、和 ' ' 組成
s 表示一個有效的表示式
'+' 不能用作一元運算(例如, "+1" 和 "+(2 + 3)" 無效)
'-' 可以用作一元運算(即 "-1" 和 "-(2 + 3)" 是有效的)
輸入中不存在兩個連續的運算子
每個數字和執行的計算將適合於一個有符號的 32位 整數
分析
本題中只含有加減法,因此優先順序只需要考慮括號。但,比起層層計算括號內的算式,不如直接去掉括號順序計算更快。
去括號要考慮什麼呢? 正負號。
若'('前符號為+,則去括號後,括號內加數的符號不變;反之加數變號。
遇到')'結束這個括號,變號標誌就退回到'('前。
————>棧存本括號對應的變號標誌
掃描字串的策略
- 空格:跳過
- 數字:連續掃描得到這個數,最後數字乘以變號標誌和當前符號
- 掃描到'+':當前符號不變
- 掃描到'-':當前符號變號
- 掃描到'(':當前符號入棧為變號標誌
- 掃描到')':變號標誌退棧
程式碼
class Solution {
public:
int calculate(string s) {
const int sLen = s.length();
// 變號標誌的棧,1表示不變號,-1表示變號
stack<int> signsStack;
signsStack.emplace(1);
// 當前數的前序符號,變號標誌棧的棧頂。一個數字的最終符號是二者乘積
int currentSign = 1, topSign = 1;
// 結果求和
int ans = 0;
// 遍歷算式
int p = 0;
while(p < sLen) {
// 跳過空格
if(s[p] == ' ') {
++p;
continue;
}
// 連續掃描數字,數字的最終符號是當前符號和變號標誌的乘積
if(s[p] >= '0' && s[p] <= '9') {
long num = 0;
while(p < sLen && s[p] >= '0' && s[p] <= '9') {
num = num * 10 + s[p] - '0';
++p;
}
ans += currentSign * topSign * num;
} else {
// 遇'(',變號情況壓棧,當前符號歸位1
if(s[p] == '(') {
signsStack.emplace(currentSign * topSign);
topSign = signsStack.top();
currentSign = 1;
// 遇')',回退到上一個狀態
} else if(s[p] == ')') {
currentSign = signsStack.top();
signsStack.pop();
topSign = signsStack.top();
// 遇'+'或'-',更新當前符號
} else if(s[p] == '+'){
currentSign = 1;
} else if(s[p] == '-') {
currentSign = -1;
}
++p;
}
}
return ans;
}
};