快手 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();
    }
}
相关推荐
用户938515635075 小时前
从 O(n²) 到 O(nlogn):一文读懂快速排序的“快”与“妙”
javascript·算法
To_OC6 小时前
手写快排次次翻车?别死背快排模板了,这才是面试官想听的底层逻辑
javascript·算法·排序算法
饼干哥哥6 小时前
Reddit VOC调研太慢?搭一个AI专家团队半小时洞察任何品类|以猫用饮水机为例
人工智能·算法·ai编程
地平线开发者8 小时前
Transformer模型部署之性能优化指南
算法
地平线开发者8 小时前
人在途中:从“编译失败”到“模型可落地”——CUDA 自定义算子
算法·自动驾驶
半个落月11 小时前
从递归到快速排序:用 JavaScript 把分治思想讲明白
javascript·算法·面试
小月土星12 小时前
JavaScript 快速排序:从 pivot、双指针到分治思想
javascript·算法·面试
小月土星12 小时前
JavaScript 递归入门:从 1 到 n 求和,再到数组扁平化
javascript·算法·面试
To_OC1 天前
LC 1 两数之和:面试第一道必考题,暴力解法直接被面试官 pass
javascript·算法·leetcode