题解 | #四则运算#

四则运算

https://www.nowcoder.com/practice/9999764a61484d819056f807d2a91f1e?tpId=37&tqId=21273&rp=1&ru=/exam/oj/ta&qru=/exam/oj/ta&sourceUrl=%2Fexam%2Foj%2Fta%3Fdifficulty%3D3%26judgeStatus%3D1%26page%3D1%26pageSize%3D50%26search%3D%26tpId%3D37%26type%3D37&difficulty=3&judgeStatus=1&tags=&title=


  1. 将一个表达式分成三部分,数字、运算符和括号部分,将括号里的表达式看做一个整体,又可以分成这样三部分,于是可以用递归解决。
  2. 遇到数字就存到栈里;遇到加减运算符接下来还是存到栈里,遇到乘除运算符就取出栈顶运算完再放进栈里;遇到括号就用递归解决括号里的表达式。
  3. 定义了一个运算符的自由度,代表该运算符前的括号是否是完整的,比如示例3+2*{1+2*[-4/(8-6)+7]}这样一个表达式中,第一个+号和第一个*号是0自由度的,其他不为0;但如果只看大括号{}里的部分即1+2*[-4/(8-6)+7],此时1后面的+号、2后面的*号变成了0自由度,这在递归中可以解决。
  4. 将原始表达式存到一个作为成员变量的字符数组,这样递归时只需要传递首尾两个参数,不需要频繁的截取数组或字符串。
  5. 计算时用的double类型,最后输出时如果小数部分为0就取整输出。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Stack;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String input = br.readLine();
        Solution sl = new Solution();
        double num = sl.getAnswer(input);
        if (Math.round(num) - num == 0) {
            System.out.println((int) num);
        } else {
            System.out.println(num);
        }
    }
}

class Solution {

    char[] chars;
    char[] brackets = {')', ']', '}'};
    char[] operators = {'+', '-', '*', '/'};

    //将表达式转换为字符数组成员变量,计算局部表达式时只需要传递两个下标
    public double getAnswer(String expression) {
        chars = expression.toCharArray();
        return calculate(0, chars.length);
    }

    public double calculate(int pos, int end) {
        Stack<Double> store = new Stack<>();

        while (pos < end) {
            char cur = chars[pos];
            double val = 0;
            if (cur == '(' || cur == '[' || cur == '{') {
                int target = findFreeTarget(chars, pos + 1, end, 1, brackets);
                val = calculate(pos + 1, target);
                pos = target + 1;
            } else if (Character.isDigit(cur)) {
                while (pos < end && Character.isDigit(chars[pos])) {
                    val = val * 10 + chars[pos] - '0';
                    pos++;
                }
            } else {
                //找到下一个自由度为0的运算符,计算这一段表达式的值
                int target = findFreeTarget(chars, pos + 1, end, 0, operators);
                switch (cur) {
                    case '+':
                        val = calculate(pos + 1, target);
                        break;
                    case '-':
                        val = -calculate(pos + 1, target);
                        break;
                    case '*':
                        val = store.pop() * calculate(pos + 1, target);
                        break;
                    default:
                        val = store.pop() / calculate(pos + 1, target);
                }
                pos = target;
            }
            store.push(val);
        }

        double answer = 0;
        while (!store.isEmpty()) {
            answer += store.pop();
        }
        return answer;
    }

    //找到下一个自由度为0的 + 号或 - 号, 定义自由度为该字符前左括号和右括号的个数
    public int findFreeTarget(char[] chars, int pos, int end, int freedom, char[] targets) {
        while (pos < end) {
            char cur = chars[pos];
            if (cur == '(' || cur == '[' || cur == '{') {
                freedom++;
            } else if (cur == ')' || cur == ']' || cur == '}') {
                freedom--;
            }
            if (freedom == 0) {
                for (char target : targets) {
                    if (cur == target) {
                        return pos;
                    }
                }
            }
            pos++;
        }
        return end;
    }
}




全部评论

相关推荐

01-09 11:18
门头沟学院 Java
作者先叠个甲:本人双非本,秋招拿到了多个大厂offer,这个过程也不容易,但是在看到很多秋招胜利之后说自己一路有多艰辛的文章,总感觉有一点不对劲,想了很久打算写一篇文章分析一下,本文仅代表作者观点,不认同的可以在评论区大家一起理性讨论。&nbsp;秋招已经结束,各类社交平台出现一大批“大厂上岸”胜利结算。文章的叙事逻辑高度相同,开篇就渲染焦虑和困惑,学习时的挑灯夜读、投递时的屡屡碰壁、面试时的如履薄冰,将过往经历包装成一步艰辛的“奋斗史”,然后最终以大厂offer的胜利结尾,字里行间全是苦尽甘来的优越感。但是在我看来,这类文章的本质是结果导向的、带有浮夸的叙事,因为其内核不是分享经验,而是借“苦难”之名...
创作小队长:你的批判视角非常犀利,尤其“结果决定叙事权”的洞察非常精准,哈哈想邀请你来成为我们的创作者🫰 但我想补充一个视角:许多分享者的初衷并非炫耀结果或者苦难,我更愿意相信他们在这个过程中付出了很多,在这场战役结束后,他们迫不及待地想被看到,记录和分享都是给自己的一个交代,而非真的教会别人什么,他们的初衷未必是想制造焦虑。求职市场的残酷、经济环境的下行、世俗价值观才是这种叙事流行的土壤,作为一个普通人无法抵抗洪流。 感谢你发起这场讨论。理想的社区,既需要这样锐利的批判来保持清醒,你的洞察非常犀利,也许会启发一些人,能逐渐改变这种叙事~
点赞 评论 收藏
分享
2025-12-04 15:23
三峡大学 FPGA工程师
不知道怎么取名字_:玩游戏都写到简历上了啊
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务