快手 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();
    }
}
相关推荐
我不会起名字3226 小时前
万字总结Golang入门项目
数据结构·经验分享·算法·golang·项目实战·复盘
6Hzlia6 小时前
【Classic 150 刷题计划】 LeetCode 14. 最长公共前缀 | C++ 纵向扫描法与防越界细节
c++·算法·leetcode
Niuguangshuo14 小时前
论文解读:CTC,端到端序列识别的开山之作
算法·语音识别
讳疾忌医丶15 小时前
深度拆解 RocksDB 内核:基于 C++17 的 FIFO 调度状态机与温度阶梯自愈设计
java·c++·算法·架构
高亦真15 小时前
今天是学习嵌入式的第37天
linux·学习·算法
不会就选b16 小时前
数据结构之排序
数据结构
罗西的思考17 小时前
[Agent Memory / 强化学习] MemPO源码学习笔记 --- (2)--- 训练
人工智能·算法·机器学习
深圳市方中禾科技18 小时前
FZH1625 LCD 驱动芯片深度评测与实战指南
算法·led
我不会起名字32219 小时前
一天一道算法题(34):回溯法的经典例题(子集)
java·数据结构·python·算法·golang·深度优先·力扣
huang57914720 小时前
哈希算法的抗碰撞机制与安全性增强策略4
算法