「这是我参与2022首次更文挑战的第27天,活动详情查看:2022首次更文挑战」
题目
227. 基本计算器 II
给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。
整数除法仅保留整数部分。
示例 1:
输入:s = "3+2*2"
输出:7
复制代码
示例 2:
输入:s = " 3/2 "
输出:1
复制代码
示例 3:
输入:s = " 3+5 / 2 "
输出:5
复制代码
解法
栈数据结构
思路
我们拿到是一整串字符串,首先得知道从哪到哪是一个数字,哪里是符号,哪些是空格要跳过,然后我们才能去进行加减乘除的运算。
- 是否符号很好判断,直接用isNaN(a)来判断即可,由于空格也不是NaN,所以满足NaN在这里一定是符号。
- 判断为数字,难点在于是这里数字一个一个字符,我们得先知道这个数字字符串有多长,我们从头开始遍历,每次遇到一个值为数字的(即
!isNaN(a) && a != ' '
),那么我们就将当前之前的数字*10,再加上当前的数字,如321为3*10 +2,然后下一次为32*10 + 1。然后遇到下一个符号,则停止累加,进入运算环节。
由于运算是有优先级的,乘除优先于加减,那么我们得先将所有的乘除运算完,将运算的结果保存起来,最后将剩下的所有数累加即可。
具体步骤如下:
- 我们先申明一个栈stack,用于存储处理完的待累加的数据,默认第一个数字入栈的运算符为 “+”
- 遍历字符串,遇到数字则根据上面的方法得到完整数字后,根据该数字之前的那个运算符来推入栈,如果是“+”则直接推入,如果是“-”则推入数字的负数,如果是“*或/”则将栈顶元素取出来和当前数字计算,再推入,由于得到完整数字是在遇到下一个符号时确定的,所以我们这里将下一个符号给保存起来,给下一个数字运算使用。
- 处理完之后,我们遍历整个栈,将所有数字累加即可。
代码
/**
* @param {string} s
* @return {number}
*/
var calculate = function(s) {
s = s.trim();
let stack = [];
let preSymbol = '+';
let num = 0;
for(let i=0;i<s.length;i++){
// isNaN(' ') == false,所以判断数字的时候需要注意空格
if(!isNaN(s[i]) && s[i] !== ' '){
num = num*10 + Number(s[i]);
}
if(isNaN(s[i]) || i == s.length -1){
switch(preSymbol){
case '+':
stack.push(num);
break;
case '-':
stack.push(-num);
break;
case '*':
stack.push(stack.pop()*num);
break;
case '/':
stack.push(parseInt(stack.pop()/num));
break;
}
preSymbol = s[i]
num = 0;
}
}
let res = 0;
while(stack.length>0){
res += stack.pop();
}
return res;
};
复制代码
复杂度分析
时间复杂度:O(n),第一遍遍历整个字符串来处理为O(n),第二遍累加最坏情况为O(n/2),故总共仍然是O(n)。
扫描二维码关注公众号,回复:
13690775 查看本文章
空间复杂度:O(n),需要一个栈来维护待相加的数,最坏情况为O(n/2),故为O(n)。