这是我参与11月更文挑战的第19天,活动详情查看:2021最后一次更文挑战」
基本计算器II(Basic Calculator)
大家小学的时候都学会了加减乘除,今天我们就用代码来实现一版自己的calcultor程序,使其能进行基本的加减乘除运算
题目
给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。
整数除法仅保留整数部分。
Given a string s which represents an expression, evaluate this expression and return its value.
The integer division should truncate toward zero.
You may assume that the given expression is always valid. All intermediate results will be in the range of [-2^31, 2^31 - 1].
Note: You are not allowed to use any built-in function which evaluates strings as mathematical expressions, such as eval().
Example
Input: s = "3+2*2"
Output: 7
Input: s = " 3/2 "
Output: 1
Input: s = " 3+5 / 2 "
Output: 5
思考线
解题思路
看到这题,我首先想到要考虑计算的优先级。由于只有加减和乘除运算,我们可以
-
先进行乘除运算后将结果和乘除运算字符串进行替换
-
再将替换后的结果进行加减运算,直到得到我们想要的结果。
那么如何去在代码中实现上面的操作呢?
基于之前学的数据结构,我觉得用栈应该是个不错的选择,因为它有后进先出的性质,基于此性质我们:
- 可以保存优先级低的运算
- 当遇到优先级高的运算也能直接取出相应的值进行计算
那么具体我们该如何设计我们的程序呢?
- 遍历字符串
s,并用变量preSign记录每个数字之前的运算符。对于第一个数字,其之前的运算符视为加号。 - 每次遍历到数字尾部,根据preSign来进行计算。
- 加号:将数字压入栈中
- 减号: 将数字的相反数压入栈中
- 乘除号:计算数字与栈顶元素,并将栈顶元素替换为计算结果。
- 如何判定遍历到了数字尾部呢? 若读到一个运算符,或者是遍历到字符串尾部,就判定遍历到了数字尾部。
- 当遍历完字符串后,如何对栈内元素进行处理? 将栈内元素进行累加,累加结果就是我们想要的结果。
代码实现
var calculate = function (s) {
s = s.replace(/ /g, '');
const stack = [];
let preSign = '+';
nums = 0;
for (let i = 0; i < s.length; i++) {
if (!isNaN(s[i])) {
nums = nums * 10 + (s[i] - '0');
}
if (isNaN(s[i]) || i === s.length - 1) {
let res;
switch (preSign) {
case '+':
stack.push(nums);
break;
case '-':
stack.push(-nums);
break;
case '*':
res = stack.pop() * nums;
stack.push(res);
break;
case '/':
res = stack.pop() / nums | 0; // 这一步是对结果取整,舍弃小数部分
console.log(res);
stack.push(res);
break;
}
preSign = s[i];
nums = 0;
}
}
console.log(stack)
return stack.reduce((pre, cur) => {
return cur + pre;
}, 0)
};
至此我们完成了本题的解答。
那么还有没有其他解决方案呢?答案是有的。
我们还可以使用双栈来解决。
对于表达式求值的这类问题,我们维护两个栈。一个 num栈用来记录数字, 一个op栈用来记录操作符,遍历字符串,遇到操作符时进行相应的计算。
需要注意的是当遇到运算符的时候,我们要考虑优先级:
-
如果操作符栈op的栈顶元素的优先级比当前遇到的操作符优先级高或者相等,则while循环进行count(计算)操作,即将数字栈num栈顶的两个元素取出来,然后和操作符栈op的栈顶操作符进行相应计算,并将计算结果压回数字栈num中。
-
否则,将当前运算符压入操作符栈
op中。
var calculate = function (s) {
s = s.replace(/ /g, '');
const pr = {
'+': 1,
'-': 1,
'*': 2,
'/': 2
}
const nums = []
const op = []
function count() {
const b = nums.pop()
const a = nums.pop()
const o = op.pop()
let res;
if (o === '+') {
res = a + b;
} else if (o === '-') {
res = a - b;
} else if (o === '*') {
res = a * b
} else {
res = a / b | 0;
}
nums.push(res)
}
for (let i = 0; i < s.length; i++) {
if (!isNaN(s[i])) {
let sum = 0;
while (i < s.length && !isNaN(s[i])) {
sum = sum * 10 + (s[i++] - '0');
}
i--;
nums.push(sum);
}else {
while (op.length && (pr[op[op.length - 1]] >= pr[s[i]])) {
count()
}
op.push(s[i])
}
}
while (op.length) {
count()
}
return nums.pop()
}
做出计算器还真不是简简单单就能搞定,如果加上()运算符的话挑战性就更强了,小伙伴们,你能做出带()的计算器吗?