BM49 表达式求值

描述

请写一个整数计算器,支持加减乘三种运算和括号。

数据范围:0\le |s| \le 1000≤∣s∣≤100,保证计算结果始终在整型范围内

要求:空间复杂度: O(n)O(n),时间复杂度 O(n)O(n)

示例1

输入:

"1+2"

返回值:

3

示例2

输入:

"(2*(3-4))*5

返回值:
-10

示例3

输入:

"3+2*3*4-1"

返回值:

扫描二维码关注公众号,回复: 14721078 查看本文章
26

题解:

(双栈解决)

第一个栈s1存储操作数(存储计算的结果)

第二个栈s2存储操作符

步骤:

第一步:将所有的字符串,去掉所有的空格字符串;

第二步:遍历该字符串,如果当前的字符是‘(’,则直接进栈;

如果当前的字符是')',则将操作符栈s2一直出栈(如果s2不为空,且s2的栈顶不为‘(’), 将该出栈的操作符和操作数栈的两个数不停的进行计算,计算的结果重新压入操作数栈中

直到操作符栈s2的栈顶为‘(’,才停止出栈,最后将s2中的栈顶元素出栈。

如果当前的字符是数字字符,则一次性的将所有的数字字符变成整数(“123”----->> 123),然后压入操作数栈中;注意记录循环的位置,要跳到已经处理的位置;

如果当前的字符是操作符,则:

       首先判断上一个字符是否也是操作符,

       如果是,则可能当前操作符不是操作符,而是负数,正数(‘-’,‘+’)

                    我们需要在操作数栈中添加一个0,作为-1  ===>0-1

       如果不是,则取出操作符栈s2的栈顶p,和当前的字符ch比较等级

                   如果栈顶的等级大于当前字符等级,则将操作符栈s2一直出栈(如果s2不为空,且s2的栈顶不为‘(’), 将该出栈的操作符和操作数栈的两个数不停的进行计算,计算的结果重新压入操作数栈中;

                  否则,将当前的字符压入s2栈中,停止出栈

最后一步:遍历完所有的字符串后

将s2中的元素全部出栈,将该出栈的操作符和操作数栈的两个数不停的进行计算,计算的结果重新压入操作数栈中

最后s1中存储的元素就是这个计算式的计算结果

代码:

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 返回表达式的值
     * @param s string字符串 待计算的表达式
     * @return int整型
     */
    //计算逻辑,从s1取出两个操作数,从s2中取出操作符,然后根据运算符进行计算即可
    public void cal(Stack<Integer> s1,Stack<Character> s2){
        if(s1.empty()||s1.size()<2) return;  //操作栈为空或小于2个数
        if(s2.empty()) return;  //操作符为空
        //操作数栈,出两个数
        int a=s1.pop(); int b=s1.pop();
        //操作符栈,出一个操作符
        char op=s2.pop();
        int ans=0;  //初始化两个数的运算结果
        if(op=='+'){
            ans=a+b;  //加法
        }
        else if(op=='-'){
            ans=b-a;  //减法 栈是倒序输出,a-b,其实栈中先输出b再输出a
        }
        else if(op=='*'){
            ans=a*b; //乘法
        }
        else{
            if(b!=0){
                ans=b/a;  //除法
            }
            else{
                return ;
            }
        }
        s1.push(ans);  //将计算结果重新置于操作数栈中
    }
    public int back(String s){
        s=s.replaceAll(" ",""); //去掉所有的空格
        Stack<Integer> s1=new Stack<>();  //存储数字
        Stack<Character> s2=new Stack<>();  //存储字符
        HashMap<Character,Integer> map=new HashMap<>();
        map.put('+',1);
        map.put('-',1);
        map.put('*',2);
        map.put('/',2);
        for(int i=0;i<s.length();i++){
            char ch=s.charAt(i);
            if(ch=='('){
                s2.push(ch);
            }
            else if(ch==')'){
                //计算到最近一个左括号为止
                while(!s2.empty()){ //如果不为空
                    if(s2.peek()!='('){  //计算到最近一个左括号为止
                        // 操作数栈出两个数。操作栈出一个操作数,计算的结果重新置于操作数栈中
                        cal(s1,s2);
                    }
                    else{//遇到了左括号'('
                        s2.pop();
                        break;  //停止出栈
                    }
                 }
             }
            else{//操作数和操作符
                if((ch-'0')>=0&&(ch-'0')<=9){//操作数
                    int j=i;  //记录操作数字符的范围
                    int u=0; //使字符的数字变成整数
                    while(j<s.length()&&(((ch=s.charAt(j))-'0')>=0&&((ch=s.charAt(j))-'0')<=9)){ //一次性读取所有的操作数
                        u=u*10+(ch-'0');
                        j++;  //一次性读取所有的数字字符
                    }
                    s1.push(u); //将形成的整数进到操作数栈中
                    i=j-1; //跳过已经遍历的数字字符
                }
                else{ //操作符
                    //为防止操作符后又是+1,-1 ,将正数,负数误判为操作符
                    //所以提前增加一个0,直接将-1变成0-1运算
                    if(i>0&&(s.charAt(i-1)=='('||s.charAt(i-1)=='+'||s.charAt(i-1)=='-')){
                        s1.push(0);
                    }
                    //新操作符入栈前,先比较操作符栈栈顶的优先级
                    //如果操作符栈不为空,且操作符栈栈顶不为‘(’
                    //栈顶的操作符等级大于等于当前的操作符
                    while(!s2.empty()&&s2.peek()!='('){
                        char pre=s2.peek(); //取栈顶
                        if(map.get(pre)>=map.get(ch)){  //如果栈顶元素等级大于等于当前操作符等级
                            cal(s1,s2);  //操作符出栈,操作数出栈两个数
                        }
                        else{  //当前操作符等级大于栈顶操作符
                            break;
                        } 
                    }//while
                    s2.push(ch);// 如果当前操作符大于栈顶的操作符,则进栈    
                 } 
              }//else
          }//for
        //遍历完所有的字符串,然后将栈中的元素全部计算
        while(!s2.empty()){
            cal(s1,s2);  //计算的结果全部存储操作数栈中
        }
        //最后的栈顶就是所有计算的结果
        return s1.peek();
    }
    public int solve (String s) {
        // write code here
       int sum=back(s);
       return sum;
    }
}

猜你喜欢

转载自blog.csdn.net/hgnuxc_1993/article/details/124149455