蓝桥杯 算法训练 ALGO-156 表达式计算

算法训练 表达式计算
时间限制:1.0s 内存限制:256.0MB
问题描述
  输入一个只包含加减乖除和括号的合法表达式,求表达式的值。其中除表示整除。
输入格式
  输入一行,包含一个表达式。
输出格式
  输出这个表达式的值。
样例输入
1-2+3*(4-5)
样例输出
-4
数据规模和约定
  表达式长度不超过100,表达式运算合法且运算过程都在int内进行。

**题目解析:
  运算优先级: 括号 → 乘除 → 加减
  例如  1-2+3*(4-5)
    (1)计算(4-5),表达式变为 1-2+3*-1
    (2)计算 3*-1,表达式变为 1-2+-3
    (3)计算 1-2,表达式变为 -1+-3
    (4)计算 -1+-3,表达式变为 -4
    (5)结果 -4
  根据这一规律,我们首先在输入的表达式两端加上括号,使程序变为重复去计算括号中的子表达式。计算规则如同上例。** 

示例代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder expression = new StringBuilder("("+br.readLine()+")");    //表达式,在输入的表达式两边加上括号
        StringBuilder temp = new StringBuilder();                                //存放临时表达式,即每次存放的都是任意一个括号中的子表达式
        while(true){
            int frontBrackets = expression.lastIndexOf("(");            //从表达式后边开始搜索,找到最后一个"("
            int backBrackets = expression.indexOf(")", frontBrackets);  //从最后一个"("的位置开始往后搜索,找到与之对应的")"

            if(frontBrackets == -1)    break;    //若再无表达式需要计算,即expression只有一个整数时,跳出循环

            temp.append(expression.substring(frontBrackets + 1 , backBrackets));    //将此括号中的表达式存入temp
            expression.delete(frontBrackets, backBrackets + 1);        //在原始表达式中将括号连同其中的表达式删除

            for(int i = 0; i < temp.length(); i++){        //从子表达式中找出运算符,根据运算原则,先乘除后加减
                if(temp.charAt(i) == '*'){                //若找到 "*" ,调用calculation进行运算
                    calculation(temp , '*' , i);
                    i = 0;                                //运算完后,i清零,方便下一次从开始位置继续寻找乘除运算符
                }

                if(temp.charAt(i) == '/'){
                    calculation(temp , '/' , i);
                    i = 0;
                }
            }

            for(int i = 0; i < temp.length(); i++){        //找完乘除运算符后,开始找加减云算符
                if(temp.charAt(i) == '+'){
                    calculation(temp , '+' , i);
                    i = 0;
                }

                if(temp.charAt(i) == '-'){
                    calculation(temp , '-' , i);
                    i = 0;
                }
            }

            expression.insert(frontBrackets, temp);        //运算完后,将结果插入在刚才删除的括号位置,构成新的表达式,继续循环计算
            temp.delete(0, temp.length());                //将temp清空,方便下一个表达式计算

        }

        System.out.println(expression);        //输出结果
    }

    /**
     * 计算表达式
     * @param src      表达式
     * @param op       操作符
     * @param location    操作符在表达式中的位置
     */
    private static void calculation(StringBuilder src, char op, int location) {
        int x = 0;    //操作数1
        int y = 0;  //操作数2
        int sum = 0;// sum = x (op) y

        String check = "0123456789+-";    //检测运算符两边的内容是否为其中数组或者正数或负数
        StringBuilder temp = new StringBuilder();    //存放运算符两边的字符

        if(location == 0)    return;        //若遇到子表示其中只有加减运算符这种情况,且遇到的第一个运算符其实是想表示一个正数或者负数的符号,则函数返回,继续寻找下一个运算符

        int k = 0;  //搜索操作符左右两边的数
        for(k = location - 1; k >= 0 && check.contains(src.charAt(k) + ""); k--){    //从运算符左边一个位置开始往前搜索,找到第一个操作数
            try{
                //若数字前边有两个运算符,第一个是为了与前边的数相连,第二个是为了表示这个数的正负,则跳出循环,执行后面的语句
                //比如: 5+(7+-5*+10),搜索到5前边时,先搜索到"-",发现前边还有一个"+",此时temp中没有运算符,则继续执行,当搜索到"+"时,发现前边没有运算符了,就跳出循环
                if((src.charAt(k) == '+' || src.charAt(k) == '-') && (src.charAt(k-1) != '+' || src.charAt(k-1) != '-' ))
                    break;
                if(temp.charAt(0) == '+' || temp.charAt(0) == '-')
                    break;

            }catch(Exception e){
//                e.printStackTrace();    //不输出异常,满足题目输出要求
            }

            temp.insert(0, src.charAt(k));    //每次都是从temp的开始位置插入内容,保证逆向搜索的内容能按照正常的顺序存入temp
            src.deleteCharAt(k);            //删除运算符前边的那个数字,若有正负号,也一并删除
        }

        x = Integer.parseInt(temp.toString());    //将搜索到的此数存入x
        temp.delete(0, temp.length());            //将temp清空

        for(k = k + 2; k < src.length() && check.contains(src.charAt(k) + ""); ){    //从运算符右边一个位置开始往后搜索,找到第二个操作数,加2是因为上边的循环语句在结束时自减了一次

            if((src.charAt(k) == '+' || src.charAt(k) == '-') && (temp.length() != 0))
                break;

            temp.append(src.charAt(k));
            src.deleteCharAt(k);
        }

        y = Integer.parseInt(temp.toString());
        temp.delete(0, temp.length());

        switch(op){
            case '+':
                sum = x + y;
                src.deleteCharAt(k-1);        //删除运算符
                src.insert(k-1, sum + "");    //将结果存入src的操作符位置(此时操作符两边的数已经从src中删除,所以插入此位置相当于用结果代替子表达式,方便下一次运算)
                break;

            case '-':
                sum = x - y;
                src.deleteCharAt(k-1);
                src.insert(k-1, sum + "");
                break;

            case '*':
                sum = x * y;
                src.deleteCharAt(k-1);
                src.insert(k-1, sum + "");
                break;

            case '/':
                sum = x / y;
                src.deleteCharAt(k-1);
                src.insert(k-1, sum + "");
                break;

            default:
                break;
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
因各个项目中需要使用根据字符串计算数值,这里写出一个算法,专门计算字符串。配有大量常用公式。只有一个人方法,直接调用即可。 类名:CustomMath 函数名:Calculations(string value) 说明:求解算式表达式字符串的值 表达式中包含的符号或函数: truncate, ceiling,floor,round,log10, sign,sinh,sqrt, asin,atan,cosh, tanh, sin,cos,tan ,abs,acos, exp,log,max,min,pow,mod,+,-,*,/,',',(,) 函数说明:(不区分大小写) truncate(num) 计算指定数的整数部分 truncate(1.23)=1 ceiling (num) 返回大于或等于指定的双精度浮点数的最小整数值 ceiling(1.23)=2 floor(num) 返回小于或等于指定双精度浮点数的最大整数 floor(1.23)=1 round(num) 将双精度浮点值舍入为最接近的整数值 round(1.23)=1 round(num,num1) 将小数值按指定的小数位数舍入 round(1.23,1)=1.2 log10(num) 返回指定数字以 10 为底的对数 log10(10)=1 sign(num) 返回表示数字符号的值 sign(1.23)=1 sinh(num) 返回指定角度的双曲正弦值 sinh(1.23)=1.5644 sqrt(num) 返回指定数字的平方根 sqrt(9)=3 sqrt(num,num1) 返回指定数字的num1根 sqrt(27,3)=3 asin(num) 返回正弦值为指定数字的角度 asin(0.5)=PI/6 atan(num) 返回正切值为指定数字的角度 atan(1)=45 cosh(num) 返回指定角度的双曲余弦值 cosh(1.23)=1.8567 tanh(num) 返回指定角度的双曲正切值 tanh(1.23)=0.8425 sin(num) 返回指定角度的正弦值 sin(PI/6)=0.5 cos(num) 返回指定角度的余弦值 sin(PI/3)=0.5 tan(num) 返回指定角度的余切值 sin(PI/4)=1 abs(num) 返回数字的绝对值 abs(-12)=12 acos(num) 返回余弦值为指定数字的角度 acos(0.5)=PI/3 exp(num) 返回 e 的指定次幂 exp(1)=2.718 log(num) 返回指定数字的自然对数(底为 e) log(e)=1 log(num,num1) 返回指定数字在使用指定底时的对数 log(e,e)=1 max(num,um1) 返回最大值 max(1,2)=2 min(num,num1) 返回最小值 min(1,2)=1 pow(num,num1) 返回指定数字的指定次幂 pow(2,2)=4 mod(num,num1) 返回余数 mod(3,2)=1 常量: PI 值:3.14159265358979323846 E 值:2.7182818284590452354 YEAR 值:当前年份 MONTH 值:当前月份 DAY 值: 当前日 HOUR 值:当前时 MINUTE 值:当前分 SECOND 值:当前秒 RANDOM 值:一个随机数(0-1 之间) 实例 系统计算:1+2*3/4-0.5=2 函数计算:1+2*3/4-0.5=2 调用方式:CustomMath.Calculations("1+2*3/4-0.5") 系统计算:(1+2)*3/4-0.5=1.75 函数计算:(1+2)*3/4-0.5=1.75 调用方式:CustomMath.Calculations("(1+2)*3/4-0.5") 系统计算:(sin(pi)+sqrt(3+5*7+(2+8/4*5+2)))/6=1.20185042515466 公式计算:(sin(pi)+sqrt(3+5*7+(2+8/4*5+2)))/6=1.20185042515466 调用方式:CustomMath.Calculations("(sin(pi)+sqrt(3+5*7+(2+8/4*5+2)))/6") 系统计算:sin(pow(3,2)/4)+3.5-9*sqrt(81)=-76.7219268031121 函数计算:sin(pow(3,2)/4)+3.5-9*sqrt(81)=-76.7219268031121 调用方式:CustomMath.Calculations("sin(pow(3,2)/4)+3.5-9*sqrt(81)")
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值