快手 CodeTop LeetCode 224.基本计算器

思路:栈解法。用栈来处理括号带来的优先级问题,将复杂的表达式拆解成多个简单的、不带括号的子表达式分别计算。

1.解题过程:

(1)如果是数字字符'0' ~ '9',那么就连续读取数字,构建完整的数值。

(2)如果是加号'+',那么就将当前的数字累加到结果中,并重置符号为正(下一个数字是正数)。

(3)如果是减号'-',逻辑同加号,将当前的数字累加到结果中,并重置符号为负(下一个数字是负数)。

(4)如果是左括号'(',遇到左括号,先保存现场,然后重置符号。

(5)如果是右括号')',遇到右括号,先把括号内的数字和符号计算完毕,然后合并回括号前的现场。

(6)别忘了加上最后一个数字。

2.复杂度分析:

(1)时间复杂度:O(n)。

(2)空间复杂度:O(n)。

附代码:

java 复制代码
class Solution {
    public int calculate(String s) {
        LinkedList<Integer> stack = new LinkedList<>();
        // 当前已经计算好的结果
        int res = 0;
        // 当前数字前面的正负号
        int preSign = 1;
        // 当前正在读取的数字
        int num = 0;
        for (char c : s.toCharArray()) {
            // 遇到数字,连续读取数字构建完整的整数
            if (c <= '9' && c >= '0') {
                num = num * 10 + (c - '0');
            }
            // 遇到加号,把当前已读到数字累加到结果res
            // 然后重置已读数字num为0,重置符号为正(下一个数字是正数) 
            else if (c == '+') {
                res += num * preSign;
                num = 0;
                preSign = 1;
            }
            // 遇到减号,把当前已读到的数字累加到结果res
            // 然后重置已读数字num为0,重置符号为负(下一个数字是负数) 
            else if (c == '-') {
                res += num * preSign;
                num = 0;
                preSign = -1;
            }
            // 遇到左括号,先保存括号前的结果和括号前的符号入栈
            // 然后重置当前已经计算好的结果为0,以开始计算括号内的结果
            // 然后重置符号为正(括号内的第一个数字默认为正) 
            else if (c == '(') {
                stack.push(res);
                stack.push(preSign);
                res = 0;
                preSign = 1;
            }
            //  遇到右括号,加上括号内剩下的最后一个数字(因为遇到操作符才将当前数字加入结果,而最后一个数字没有遇到操作符,需要单独手动处理),然后括号里的数字已加减完毕
            // 然后乘上括号前的符号
            // 然后加上括号前的计算结果
            else if (c == ')') {
                res += num * preSign;
                // 括号外如果有数字会从新的num开始读取,否则最后return就是加个0,不会多加导致结果错误
                num = 0;
                // 这里不需要重置preSign
                // 因为遇到右括号代表括号内计算完毕,之后括号外的计算会使用从栈中弹出的符号,而不是preSign
                // 下一次遇到操作符时,根据之前的逻辑,也会会重新设置preSign
                res *= stack.pop();
                res += stack.pop();
            }
        }
        // 由于遇到操作符才将当前数字加入结果
        // 而最后一个数字没有遇到操作符
        // 因此需要单独手动处理
        return res + preSign * num;
    }
}

ACM模式:

java 复制代码
import java.util.LinkedList;
import java.util.Scanner;

class Solution {
    public int calculate(String s) {
        LinkedList<Integer> stack = new LinkedList<>();
        // 当前已经计算好的结果
        int res = 0;
        // 当前数字前面的正负号
        int preSign = 1;
        // 当前正在读取的数字
        int num = 0;

        for (char c : s.toCharArray()) {
            // 遇到数字,连续读取数字构建完整的整数
            if (c <= '9' && c >= '0') {
                num = num * 10 + (c - '0');
            }
            // 遇到加号,把当前已读到数字累加到结果res
            // 然后重置已读数字num为0,重置符号为正(下一个数字是正数)
            else if (c == '+') {
                res += num * preSign;
                num = 0;
                preSign = 1;
            }
            // 遇到减号,把当前已读到的数字累加到结果res
            // 然后重置已读数字num为0,重置符号为负(下一个数字是负数)
            else if (c == '-') {
                res += num * preSign;
                num = 0;
                preSign = -1;
            }
            // 遇到左括号,先保存括号前的结果和括号前的符号入栈
            // 然后重置当前已经计算好的结果为0,以开始计算括号内的结果
            // 然后重置符号为正(括号内的第一个数字默认为正)
            else if (c == '(') {
                stack.push(res);
                stack.push(preSign);
                res = 0;
                preSign = 1;
            }
            // 遇到右括号,加上括号内剩下的最后一个数字
            // 然后乘上括号前的符号,然后加上括号前的计算结果
            else if (c == ')') {
                res += num * preSign;
                // 括号外如果有数字会从新的num开始读取,否则最后return就是加个0,不会多加导致结果错误
                num = 0;
                // 这里不需要重置preSign
                // 因为遇到右括号代表括号内计算完毕,之后括号外的计算会使用从栈中弹出的符号,而不是preSign
                // 下一次遇到操作符时,根据之前的逻辑,也会会重新设置preSign
                res *= stack.pop();
                res += stack.pop();
            }
        }

        // 由于遇到操作符才将当前数字加入结果
        // 而最后一个数字没有遇到操作符,因此需要单独手动处理
        return res + preSign * num;
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 读取表达式字符串(可能包含空格)
        String s = scanner.nextLine();

        // 计算结果
        Solution solution = new Solution();
        int result = solution.calculate(s);

        // 输出结果
        System.out.println(result);

        scanner.close();
    }
}
相关推荐
ting94520001 天前
Humalike X Hermes 深度技术剖析:单指令注入群聊社交智能的底层架构、算法与跨 IM 平台实现
人工智能·算法·架构
吴声子夜歌1 天前
Java面试——算法
java·算法·面试
evans在进步1 天前
LeetCode 64:最小路径和——Java 原地动态规划详解
java·leetcode·动态规划
h_a_o777oah1 天前
【图论】Tarjan 缩点:解决有向图中环的问题
c++·算法·图论·acm·强连通分量·缩点·tarjan
Tisfy1 天前
LeetCode 1386.安排电影院座位:哈希表+位运算
算法·leetcode·散列表·题解·哈希表
Nil2081 天前
leetcode 199二叉树的右视图
算法·leetcode·深度优先
M78佐菲1 天前
c语言学习笔记:排序与查找方法整理
linux·c语言·笔记·学习·算法
AI备案指南-满满1 天前
人工智能拟人化互动服务安全自评估报告的评估要点有哪些?
人工智能·算法·安全·机器人·大模型备案·算法备案
LuminousCPP1 天前
数据结构‑二叉树(二):二叉堆从零实现|Heap结构设计 + 建堆优化 + 堆排序深度解析
c语言·数据结构·笔记·二叉树