以下为ChatGPT自动生成的解答,正确与否请自行判断。
BFE.devAI解答 - JavaScript 代码题
124. 四则运算的结果
思路: 首先,我们需要将字符串转换成tokens,处理的方式参考119. 创建一个tokenizer ,即去掉空白字符后,将整个字符串分割成若干个token。
接下来,我们需要考虑计算的步骤,我们可以通过两个栈来实现,一个栈用来存储数字,另一个栈用来存储运算符号。从左到右遍历tokens,对于每个token,执行以下操作:
- 如果当前token是数字,将其压入数字栈中。
- 如果当前token是运算符号,分两种情况:
- 如果当前运算符号是左括号
(
,将其压入运算符号栈中。 - 如果当前运算符号是右括号
)
,则反复弹出运算符号栈中的元素,直到遇到左括号为止。在此过程中,从数字栈中弹出两个数字并执行相应运算,将结果压回数字栈中。 - 如果当前运算符号不是左括号或右括号,则将其与运算符号栈栈顶元素进行比较,如果当前运算符的优先级不高于栈顶运算符的优先级,则从数字栈中弹出两个数字并执行栈顶运算符的相应运算。将结果压回数字栈中。重复比较操作直到当前运算符的优先级高于栈顶运算符的优先级,然后将当前运算符压入运算符栈中。
- 如果当前运算符号是左括号
- 对于最后一个token,如果其是数字,则将其压入数字栈中,如果是运算符,执行与上一步类似的操作,直到所有的token处理完毕为止。
- 最后,从数字栈中弹出唯一的数字即为计算结果。
需要注意:
- 运算符的优先级,乘和除的优先级高于加和减。
- 当遇到除法计算时,需要判断除数是否为0。若为0,则返回Infinity或者- Infinity 。
- 当遇到负数计算时,需要处理负号,可以将减号判断是否是负号,若是,则将其转为减号。
- 当遇到多个连续的符号,可以将其当作一个符号处理,例如“- 1+23”即为“-1+23”。
完整代码:
function calculate(str) {
// 将字符串转换成tokens
const tokens = tokenize(str);
// 运算符优先级
const priority = {
'+': 1,
'-': 1,
'*': 2,
'/': 2,
};
// 数字栈和运算符栈
const numStack = [];
const opStack = [];
// 遍历tokens
tokens.forEach(token => {
if (isNumber(token)) {
// 如果是数字,将其压入数字栈中
numStack.push(+token);
} else if (token === '(') {
// 如果是左括号,将其压入运算符栈中
opStack.push(token);
} else if (token === ')') {
// 如果是右括号,弹出运算符栈中的元素,并执行相应运算
while (opStack[opStack.length - 1] !== '(') {
const op = opStack.pop();
const num2 = numStack.pop();
const num1 = numStack.pop();
numStack.push(calculateResult(num1, op, num2));
}
opStack.pop(); // 弹出左括号
} else {
// 如果是运算符,比较优先级,并执行相应运算
while (
opStack.length > 0 &&
opStack[opStack.length - 1] !== '(' &&
priority[token] <= priority[opStack[opStack.length - 1]]
) {
const op = opStack.pop();
const num2 = numStack.pop();
const num1 = numStack.pop();
numStack.push(calculateResult(num1, op, num2));
}
opStack.push(token);
}
});
// 处理剩余的运算符
while (opStack.length > 0) {
const op = opStack.pop();
const num2 = numStack.pop();
const num1 = numStack.pop();
numStack.push(calculateResult(num1, op, num2));
}
return numStack.pop();
}
// 判断一个token是否为数字
function isNumber(token) {
return /^\d+$/.test(token);
}
// 计算两个数字的运算结果
function calculateResult(num1, op, num2) {
let result;
switch (op) {
case '+':
result = num1 + num2;
break;
case '-':
result = num1 - num2;
break;
case '*':
result = num1 * num2;
break;
case '/':
if (num2 === 0) {
return num1 > 0 ? Infinity : -Infinity;
}
result = num1 / num2;
break;
}
return result;
}
// 将字符串转换成tokens
function tokenize(str) {
const tokens = [];
let i = 0;
while (i < str.length) {
const char = str[i];
if (char === ' ') {
// 跳过空格
i++;
continue;
}
if (isNumberChar(char)) {
// 合并数字字符
let j = i + 1;
while (j < str.length && isNumberChar(str[j])) {
j++;
}
tokens.push(str.slice(i, j));
i = j;
continue;
}
// 处理连续的符号
if (char === '-' || char === '+') {
if (isOp(tokens[tokens.length - 1]) || !tokens.length) {
let j = i + 1;
while (j < str.length && str[j] === char) {
j++;
}
const sign = j % 2 === 0 ? '+' : char;
tokens.push(sign);
i = j;
continue;
}
}
// 其他情况直接作为token
tokens.push(char);
i++;
}
return tokens;
}
// 判断一个字符是否为数字字符
function isNumberChar(char) {
return /\d/.test(char);
}
// 判断一个token是否为运算符
function isOp(token) {
return ['+', '-', '*', '/', '(', ')'].indexOf(token) !== -1;
}