写在前面
本专栏专注于分析与讲解【面试经典150】算法,两到三天更新一篇文章,欢迎催更……
专栏内容以分析题目为主,并附带一些对于本题涉及到的数据结构等内容进行回顾与总结,文章结构大致如下,部分内容会有增删:
- Tag:介绍本题牵涉到的知识点、数据结构;
- 题目来源:贴上题目的链接,方便大家查找题目并完成练习;
- 题目解读:复述题目(确保自己真的理解题目意思),并强调一些题目重点信息;
- 解题思路:介绍一些解题思路,每种解题思路包括思路讲解、实现代码以及复杂度分析;
- 知识回忆:针对今天介绍的题目中的重点内容、数据结构进行回顾总结。
Tag
【栈】
题目来源
解题思路
本题参考 官方题解。
方法一:括号展开+栈
思路
由于字符串除了数字与括号外,只有加号和减号两种运算符。因此,如果展开表达式中所有的括号,则得到的新表达式中,数字本身不会发生变化,只是每个数字前面的符号会发生变化。
因此,我们考虑使用一个取值为 {−1,+1}
的整数 sign
代表「当前」的符号。根据括号表达式的性质,它的取值:
- 与字符串中当前位置的运算符有关;
- 如果当前位置处于一系列括号之内,则也与这些括号前面的运算符有关:每当遇到一个以 −-− 号开头的括号,则意味着此后的符号都要被「翻转」。
考虑到第二点,我们需要维护一个栈 ops
,其中栈顶元素记录了当前位置所处的每个括号共同作用下的符号。例如,对于字符串 1+2+(3-(4+5))
:
- 扫描到
1+2
时,由于当前位置没有被任何括号所包含,则栈顶元素为初始值+1
; - 扫描到
1+2+(3
时,当前位置被一个括号所包含,该括号前面的符号为+
号,因此栈顶元素依然+1
; - 扫描到
1+2+(3-(4
时,当前位置被两个括号所包含,分别对应着+
号和−
号,由于+
号和−
号合并的结果为−
号,因此栈顶元素变为−1
。
在得到栈 ops
之后, sign
的取值就能够确定了:如果当前遇到了 +
号,则更新 sign = ops.top()
;如果遇到了遇到了 −
号,则更新 sign = ops.top()
。
然后,每当遇到 (
时,都要将当前的 sign
取值压入栈中;每当遇到 )
时,都从栈中弹出一个元素。这样,我们能够在扫描字符串的时候,即时地更新 ops
中的元素。
代码
class Solution {
public:
int calculate(string s) {
// 只有正负号,因此数字不会改变,只是每个数字前面的符号会变
stack<int> stk;
int sign = 1;
stk.emplace(sign);
int i = 0, n = s.size();
int ret = 0;
while(i < n) {
if (s[i] == ' ') {
++i;
}
else if(s[i] == '+') {
sign = stk.top();
++i;
}
else if (s[i] == '-') {
sign = -stk.top();
++i;
}
else if (s[i] == '(') {
stk.emplace(sign);
++i;
}
else if (s[i] == ')') {
stk.pop();
++i;
}
else {
long long num = 0;
while(i < n && s[i] >= '0' && s[i] <= '9') {
num = num * 10 + s[i] - '0';
++i;
}
ret += sign * num;
}
}
return ret;
}
};
复杂度分析
时间复杂度:
O
(
n
)
O(n)
O(n),
n
n
n 是字符串 s
的长度。
空间复杂度: O ( n ) O(n) O(n)。
写在最后
如果您发现文章有任何错误或者对文章有任何疑问,欢迎私信博主或者在评论区指出 💬💬💬。
如果大家有更优的时间、空间复杂度的方法,欢迎评论区交流。
最后,感谢您的阅读,如果有所收获的话可以给我点一个 👍 哦。