Q26-code224-基本计算器
实现思路
1 双栈实现
1 双栈设计:
- 数字栈:存储所有数字
- 操作符栈:存储运算符和括号
2 核心思想:
- 遇到数字直接入栈
- 遇到运算符时,比较优先级,决定是否计算
- 遇到括号时特殊处理
- 保持较高优先级的运算符先计算
3 优先级处理:
- 括号具有最高优先级
- 乘除 > 加减
- 同级运算符从左到右计算
4 统一处理负数
- 将负数统一转换为减法运算
- -n 转换为 0-n
参考文档
代码实现
1 方法1: 双栈实现 时间复杂度 O(n) 空间复杂度:O(n)
function calculate(s: string): number {
const opes = [], nums = [0];
// 隐藏的优选级:()括号 的优先级最高
const opePriority = { "+": 1, "-": 1, "*": 2, "/": 2 };
let lastChar = "";
// 替换掉所有空格
s = s.replace(/\s/g, "");
// 遍历字符串
for (let char of s) {
// 是左括号
if (char === "(") {
opes.push(char);
} else if (/\d/.test(char)) {
// 易错点1: 是数字类型的字符串,如果上一个也是数字,那么需要和上一个数字拼接起来
if (/\d/.test(lastChar)) {
nums[nums.length - 1] = nums.at(-1) * 10 + +char;
} else {
nums.push(+char);
}
} else if (char === ")") {
// 是右括号:优先级最高,说明需要进行运算,直到运行到左括号为止
while (opes.at(-1) !== "(") getCal(nums, opes);
// 运算完成后,让左括号出栈
opes.pop();
} else {
// 说明是负号 或者 运算操作符
// 先处理是负号的情况:前面的一位是 (、+、-
// 不包含 * 和 /,是因为数学规范里, * 和 / 后面的负数需要用括号包起来,所以这里无需考虑
if (["(", "+", "-"].includes(lastChar)) nums.push(0);
// 易错点2: 如果目前操作栈顶的优先级 >= 当前的运算符,那么就需要先进行运算
// 这里需要注意可能之前有多个运算符优先级都 >= 当前的运算符,所以需要用 while循环
while ((opePriority[opes.at(-1)] ?? -1) >= opePriority[char]) {
getCal(nums, opes);
}
// 存入当前运算符
opes.push(char);
}
lastChar = char;
}
// 易错点4: 当遍历完字符串后,可能栈中还有运算符,此时 需要进行剩余值计算
while (opes.length) getCal(nums, opes);
return nums.at(-1);
};
function getCal(nums, opes) {
const [v2, v1] = [nums.pop(), nums.pop()];
const ope = opes.pop();
const fnMap = {
"+": (a, b) => a + b,
"-": (a, b) => a - b,
"*": (a, b) => a * b,
"/": (a, b) => ~~(a / b),
};
const fn = fnMap[ope];
nums.push(fn(v1, v2));
}
code20- 有效的括号
实现思路
方法1: map + 栈
- 需要注意 只有遇到false才能提前返回,为true还得继续查看后续字符
- 注意 最后还需要检查栈内是否有 多余的不成对的左字符
参考文档
代码实现
1 方法1: map + 栈 时间复杂度: O(n); 空间复杂度(n)
function isValid(s: string): boolean {
let st = [];
const pairs = new Map([
['{', '}'],
['(', ')'],
['[', ']'],
]);
for (let char of s) {
if (pairs.has(char)) {
st.push(char);
} else {
// 说明当前字符char是右字符串,判断closeTag和char是否相等
const closeTag = pairs.get(st.pop());
// 易错点1: 不相等时可以提前返回,但是相等时需要继续处理下一个字符
if (char !== closeTag) return false;
}
}
// 易错点2: 防止有多余的左字符
return st.length === 0;
}