蓝桥杯 算法训练 表达式计算 java

Algo156 算法训练 表达式计算

题目如下:
image-20200718155838701

这道题也挺经典的,虽然大部分人都用后缀表达式来写,但我打算用我脑子里第一时间想到的方法来写,java评测在100ms-200ms左右,效率虽然不高,但勉强能用。而且这算法没那么高大上,想想就出来了。

第一步就是简单化,首先我就想到怎么把括号给搞掉,这个括号毕竟不算运算符,挺麻烦的。最后我打算把每个括号内的表达式提取出来,算完了再用结果把原来的括号+括号内的表达式都替换掉。比如1-2+3×(4-5),会先把4-5提出来,得到结果为-1,原来表达式变成1-2+3×-1,在把这个表达式解出来即可,所以核心就是解没有括号的表达式,只有加减乘除还是简单的。

第二步就是只有加减乘除的表达式怎么解决啊,考虑到运算符的优先级不同,只能用到栈了。

代码如下,除了核心的运算外,我的注释足以说明 核心用下列来说明

比如一个 1-2×3+4×5/1

1.首先会把1放到数栈里,然后判断其后的符号是-,也直接存到符号栈里 这时数栈为1 符号栈为-

2.第二次循环,会把2存到数栈,然后发现其后的符号是×,这时不会把×存到栈里,而是直接运算调,这是会把2从栈中取出,然后在获取下一个数3,运算一下得到6,把这个6再存到栈中,这时候数栈为1,6。符号栈为-

3.开始第三轮循环,因为我有判断,之前进行的是乘或者除的话,这轮就不会存数字,因为3已经被上一轮的乘用掉了,所以这轮直接取符号,发现符号是一个+,这时我会看符号栈是否为空,不为空就取出来运算,因为在符号栈里的只可能是-和+,所以这没优先级,把之前存的运算掉即可,但运算后的结果和这轮本要存的符号还是要存到栈里,这轮结束,数栈为-5(1减6所得),符号栈为+

4.上述三轮结束其实表达式已经变为-5+4×5/1了,剩下的计算过程类似,可以自己推导下。

package algo;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description: 算法训练 表达式计算
 * @ClassName: Algo156
 * @author: fan.yang
 * @date: 2020/07/18 10:36
 */
public class Algo156 {

    /**
     * 这个计算函数只处理不包括括号的表达式
     */
    public static int calculation(String str){
        //数栈
        Stack<Integer> stack1 = new Stack<>();
        //符号栈
        Stack<Character> stack2 = new Stack<>();
        //这个过程就算提取数字和符号的
        char[] array = str.toCharArray();
        List<Character> symbol = new ArrayList<>();
        for(int i = 1;i < array.length;i++){
            if(!Character.isDigit(array[i]) && Character.isDigit(array[i - 1])){
                symbol.add(array[i]);
                array[i] = ' ';
            }
        }
        List<Integer> num = Arrays.asList(String.valueOf(array).split(" ")).stream()
                .map(e -> Integer.valueOf(e)).collect(Collectors.toList());
        //下面就算运用双栈来计算了 这个还是画个图比较好
        boolean flag = true;
        for(int i = 0;i < num.size();i++){
            if(flag){
                stack1.push(num.get(i));
            }
            if(i == symbol.size()){
                break;
            }
            if(symbol.get(i) == '-' || symbol.get(i) == '+'){
                flag = true;
                if(!stack2.empty()){
                    int a = stack1.pop();
                    int b = stack1.pop();
                    stack1.push(stack2.pop() == '-' ? b - a : b + a);
                }
                stack2.push(symbol.get(i));
            }else{
                flag = false;
                int a = stack1.pop();
                int b = num.get(i + 1);
                if(symbol.get(i) == '*'){
                    stack1.push(a * b);
                }else{
                    stack1.push(a / b);
                }
            }
        }
        //因为上述循环可能会留下一组 加 减操作  所以这里只需要判断下符号栈了还有没有
        //符号栈不为空就最后操作一下
        if(stack2.empty()){
            return stack1.pop();
        }else{
            int a = stack1.pop();
            int b = stack1.pop();
            return stack2.pop() == '-' ? b - a : b + a;
        }
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        StringBuffer sb = new StringBuffer(scanner.next());
        //这个indexOf就是判断表达式还有没有括号
        while(sb.indexOf("(") != -1){
            //这里为啥要用lastIndexOf 考虑到会有多层括号,当然要从里面那层开始
            //就算都是同一层的括号,我从哪里开始都一样的
            int left = sb.lastIndexOf("(");
            //获取与left括号对应的右括号
            int right = sb.indexOf(")" , left);
            //截取上述括号之间的表达式
            String str = sb.substring(left + 1 , right);
            int num = calculation(str);
            //得到结果后覆盖
            sb.replace(left , right + 1 , num + "");
        }
        //去除掉括号 就只剩下基本的加减乘除表达式了 最后调一次计算函数即可
        System.out.println(calculation(sb.toString()));
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值