「这是我参与11月更文挑战的第8天,活动详情查看:2021最后一次更文挑战」
题目
227. 基本计算器 II
给你一个字符串表达式 s
,请你实现一个基本计算器来计算并返回它的值。
整数除法仅保留整数部分。
示例 1:
输入: s = "3+2*2"
输出: 7
复制代码
示例 2:
输入: s = " 3/2 "
输出: 1
复制代码
示例 3:
输入: s = " 3+5 / 2 "
输出: 5
复制代码
提示:
1 <= s.length <= 3 * 105
s
由整数和算符('+', '-', '*', '/')
组成,中间由一些空格隔开s
表示一个 有效表达式- 表达式中的所有整数都是非负整数,且在范围
[0, 231 - 1]
内 - 题目数据保证答案是一个 32-bit 整数
思路
- 先通过字符串的
replace
把表达式中的空格全都去掉; - 一次遍历,对数据进行切割,明确一点:先乘除再加减;
- 定义变量
prev
记录表达式, 遇到"+"或者"-"就进行切割, 然后对表达式进行求解, 因为这时候的表达式可能含有"*"或者"/"; - 计算乘除:定义变量
lastFlag
记录当前出现的符号,第一轮从1开始开始当前值, 下一轮就根据lastFlag
判断执行乘法还是除法,除法记得要向下取整; - 定义变量
result
, 从第二个"*"或者"/"开始,不断统计前面的表达式, 记得要统计上最后一个数字,你可以再循环结束再调用一次计算,这里我选择循环加一次,在最后一次去进行计算; - 计算加减: 定义变量
lastFlag
记录当前出现的符号,第一轮从0开始加上当前值, 下一轮就根据lastFlag
判断执行加法还是减法; - 定义变量
result
, 累加每一个切割出来的表达式的结果。
实现
/**
* @param {string} s
* @return {number}
*/
function calculate(s) {
// 先去除括号
s = s.replace(" ", "");
// 根据 +- 切割, 然后执行 * /
const n = s.length;
let prev = "";
let result = 0;
// 记录最后一个出现的符号,决定我们待会儿加还是减
let lastFlag = "+";
for (let i = 0; i <= n; i++) {
// 如果是加减符号,就计算前面的prev,有乘除先执行计算
// i === n 是为了统计最后一个数字的运算,骚操作
if (s[i] === "+" || s[i] === "-" || i === n) {
// 计算加减法的表达式
let number = getStringValue(prev);
if (lastFlag === "-") {
number *= -1;
}
result += number;
lastFlag = s[i];
prev = "";
} else {
prev += s[i];
}
}
return result;
};
// 计算乘除表达式
function countStringValue(s) {
const n = s.length;
// prev 用来记录当前的数字
let prev = "";
// 乘除记得从1开始, 不能从0开始
let result = 1;
// 统计最后一个出现的字符是乘法还是除法
let lastFlag = "*";
for (let i = 0; i <= n; i++) {
// 如果是符号,说明前面的数字到头了,先计算上一轮的结果
// 比如 3 * 4 / 5 ,到 "/" 的时候计算 前面 3 * 4 的值
// i === n 是为了把最后一轮的结果执行
if (s[i] === "*" || s[i] === "/" || i === n) {
// 除法需要向下取整, 写法多样
// ~~5.1 === 5.1 | 0 === Math.floor(5.1) 前两个是位运算
if (lastFlag === "/") {
result = ~~(result / Number(prev));
} else {
result *= Number(prev)
}
// 记录当前的符号,下一轮拿到完整的第二个数字再执行运算
lastFlag = s[i];
prev = "";
} else {
prev += s[i];
}
}
return result;
}
复制代码
看懂了的小伙伴可以点个关注、咱们下道题目见。如无意外以后文章都会以这种形式,有好的建议欢迎评论区留言。