题解 | #四则运算#

四则运算

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;
    }
}




全部评论

相关推荐

点赞 评论 收藏
分享
05-12 22:16
已编辑
北京邮电大学 研发工程师
牛客30236098...:0offer+1 滴滴都不给我面 佬没投鹅吗,鹅应该很喜欢北邮吧
投递美团等公司10个岗位
点赞 评论 收藏
分享
06-13 17:33
门头沟学院 Java
顺序不记了,大致顺序是这样的,有的相同知识点写分开了1.基本数据类型2.基本数据类型和包装类型的区别3.==和equals区别4.ArrayList与LinkedList区别5.hashmap底层原理,put操作时会发生什么6.说出几种树型数据结构7.B树和B+树区别8.jvm加载类机制9.线程池核心参数10.创建线程池的几种方式11.callable与runnable区别12.线程池怎么回收线程13.redis三剑客14.布隆过滤器原理,不要背八股,说说真正使用时遇到了问题没有(我说没有,不知道该怎么回答了)15.堆的内存结构16.自己在写项目时有没有遇见过oom,如何处理,不要背八股,根据真实经验,我说不会17.redis死锁怎么办,watchdog机制如何发现是否锁过期18.如何避免redis红锁19.一个表性别与年龄如何加索引20.自己的项目的QPS怎么测的,有没有真正遇到大数量表21.说一说泛型22.springboot自动装配原理23.springmvc与springboot区别24.aop使用过嘛?动态代理与静态代理区别25.spring循环依赖怎么解决26.你说用过es,es如何分片,怎么存的数据,1000万条数据怎么写入库中27.你说用limit,那么在数据量大之后,如何优化28.rabbitmq如何批次发送,批量读取,答了延迟队列和线程池,都不对29.计网知不知道smtp协议,不知道写了对不对,完全听懵了30.springcloud知道嘛?只是了解反问1.做什么的?短信服务,信息量能到千万级2.对我的建议,基础不错,但是不要只背八股,多去实际开发中理解。面试官人不错,虽然没露脸,但是中间会引导我回答问题,不会的也只是说对我要求没那么高。面完问我在济宁生活有没有困难,最快什么时候到,让人事给我聊薪资了。下午人事打电话,问我27届的会不会跑路,还在想办法如何使我不跑路,不想扣我薪资等。之后我再联系吧,还挺想去的😭,我真不跑路哥😢附一张河科大幽默大专图,科大就是大专罢了
查看30道真题和解析
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

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