Implement a basic calculator to evaluate a simple expression string.
The expression string may contain open (
and closing parentheses )
, the plus +
or minus sign -
, non-negativeintegers and empty spaces .
Example 1:
Input: "1 + 1" Output: 2
Example 2:
Input: " 2-1 + 2 " Output: 3
Example 3:
Input: "(1+(4+5+2)-3)+(6+8)" Output: 23
Note:
- You may assume that the given expression is always valid.
- Do not use the
eval
built-in library function.
這道題讓我們實現一個基本的計算器來計算簡單的算數表達式,而且題目限制了表達式中只有加減號,數字,括號和空格,沒有乘除,那么就沒啥計算的優先級之分了。於是這道題就變的沒有那么復雜了。我們需要一個棧來輔助計算,用個變量sign來表示當前的符號,我們遍歷給定的字符串s,如果遇到了數字,由於可能是個多位數,所以我們要用while循環把之后的數字都讀進來,然后用sign*num來更新結果res;如果遇到了加號,則sign賦為1,如果遇到了符號,則賦為-1;如果遇到了左括號,則把當前結果res和符號sign壓入棧,res重置為0,sign重置為1;如果遇到了右括號,結果res乘以棧頂的符號,棧頂元素出棧,結果res加上棧頂的數字,棧頂元素出棧。代碼如下:
解法一:
class Solution { public: int calculate(string s) { int res = 0, sign = 1, n = s.size(); stack<int> st; for (int i = 0; i < n; ++i) { char c = s[i]; if (c >= '0') { int num = 0; while (i < n && s[i] >= '0') { num = 10 * num + (s[i++] - '0'); } res += sign * num; --i; } else if (c == '+') { sign = 1; } else if (c == '-') { sign = -1; } else if (c == '(') { st.push(res); st.push(sign); res = 0; sign = 1; } else if (c == ')') { res *= st.top(); st.pop(); res += st.top(); st.pop(); } } return res; } };
下面這種方法和上面的基本一樣,只不過對於數字的處理略微不同,上面的方法是連續讀入數字,而這種方法是使用了一個變量來保存讀入的num,所以在遇到其他字符的時候,都要用sign*num來更新結果res,參見代碼如下:
解法二:
class Solution { public: int calculate(string s) { int res = 0, num = 0, sign = 1, n = s.size(); stack<int> st; for (int i = 0; i < n; ++i) { char c = s[i]; if (c >= '0') { num = 10 * num + (c - '0'); } else if (c == '+' || c == '-') { res += sign * num; num = 0; sign = (c == '+') ? 1 : -1; } else if (c == '(') { st.push(res); st.push(sign); res = 0; sign = 1; } else if (c == ')') { res += sign * num; num = 0; res *= st.top(); st.pop(); res += st.top(); st.pop(); } } res += sign * num; return res; } };
在做了Basic Calculator III之后,再反過頭來看這道題,發現遞歸處理括號的方法在這道題也同樣適用,我們用一個變量cnt,遇到左括號自增1,遇到右括號自減1,當cnt為0的時候,說明括號正好完全匹配,這個trick在驗證括號是否valid的時候經常使用到。然后我們就是根據左右括號的位置提取出中間的子字符串調用遞歸函數,返回值賦給num,參見代碼如下:
解法三:
class Solution { public: int calculate(string s) { int res = 0, num = 0, sign = 1, n = s.size(); for (int i = 0; i < n; ++i) { char c = s[i]; if (c >= '0' && c <= '9') { num = 10 * num + (c - '0'); } else if (c == '(') { int j = i, cnt = 0; for (; i < n; ++i) { if (s[i] == '(') ++cnt; if (s[i] == ')') --cnt; if (cnt == 0) break; } num = calculate(s.substr(j + 1, i - j - 1)); } if (c == '+' || c == '-' || i == n - 1) { res += sign * num; num = 0; sign = (c == '+') ? 1 : -1; } } return res; } };
類似題目:
Evaluate Reverse Polish Notation
Different Ways to Add Parentheses
參考資料:
https://leetcode.com/problems/basic-calculator/
https://leetcode.com/problems/basic-calculator/discuss/62361/Iterative-Java-solution-with-stack
https://leetcode.com/problems/basic-calculator/discuss/62362/JAVA-Easy-Version-To-Understand!!!!!