[编程题] 四则运算

[编程题] 四则运算

题目描述

请实现如下接口

/* 功能:四则运算
* 输入:strExpression:字符串格式的算术表达式,如: "3+2*{1+2*[-4/(8-6)+7]}"
* 返回:算术表达式的计算结果
*/

public static int calculate(String strExpression)
{
    /* 请实现*/
    return 0;
} 

约束:

  1. pucExpression字符串中的有效字符包括[‘0’-‘9’],‘+’,‘-’, ‘*’,‘/’ ,‘(’, ‘)’,‘[’, ‘]’,‘{’ ,‘}’。
  2. pucExpression算术表达式的有效性由调用者保证;

输入描述:

输入一个算术表达式

输出描述:

得到计算结果

输入例子1:

3+2*{1+2*[-4/(8-6)+7]}

输出例子1:

25

个人方法(python)

# !/usr/bin/env python2
# -*- coding:utf-8 -*-

opts = '+-*/()[]{}'
Wopt = {'(':0,'[':1,'{':2,'+':3,'-':3, '*':4, '/':4}

# 字符串 转 中缀表达式(infix)  : str->list
# 目的为了 分离 多位的整数、负数以及运算符
def str2infix(line):
    infix = []
    numtmp = ''
    for ch in line:
        if ch not in opts:
            numtmp += ch
        else:
            if ch == '-':  # 分离负数
                if len(infix) != 0:
                    if infix[-1] in "([{" and numtmp=='':
                        numtmp += ch
                        continue
            if numtmp != '':
                infix.append(numtmp)
                numtmp = ''
            infix.append(ch)

    if numtmp != '':
        infix.append(numtmp)

    return infix
# 中缀表达式(infix) 转 后缀表达式(posfix)
def infix2posfix(infix):
    posfix = []
    oprtmp = []
    for v in infix:
        if v not in opts:
            posfix.append(v)
        else:
            if len(oprtmp) == 0:
                oprtmp.append(v)
            elif v in '([{':
                oprtmp.append(v)
            elif v in ')]}':
                while True:
                    ele = oprtmp.pop()
                    if ele in '([{':
                        break
                    # posfix.append(ele)
                    # if Wopt[ele] < Wopt[oprtmp[-1]]:
                    posfix.append(ele)
                        # break

            elif Wopt[v] <= Wopt[oprtmp[-1]]:
                while Wopt[v] <= Wopt[oprtmp[-1]]:
                    posfix.append(oprtmp.pop())
                    if len(oprtmp) == 0:
                        break
                oprtmp.append(v)
            else:
                oprtmp.append(v)

    while len(oprtmp) != 0:
        posfix.append(oprtmp.pop())
    return posfix
# 后缀表达式求值
def calculate(posfix):
    expr = []
    for ele in posfix:
        if ele in '-+/*':
            n1, n2 = expr.pop(), expr.pop()
            if ele == '+':
                expr.append(n2 + n1)
            elif ele == '-':
                expr.append(n2 - n1)
            elif ele == '*':
                expr.append(n2 * n1)
            else:
                expr.append(n2 / n1)
        else:
            expr.append(int(ele))
    return expr

# 字符串中的有效字符包括[‘0’-‘9’],‘+’,‘-’, ‘*’,‘/’ ,‘(’, ‘)’,‘[’, ‘]’,‘{’ ,‘}’。
try:
    while True:
        line = raw_input()
        # line = '3+2*{1+2*[-4/(8-6)+7]}'
        # line = '3*5+8-0*3-6+0+0'
        # line = '5-3+9*6*(6-10-2)'
        # line = '3-10+(0+(10+5+3)-10)'
        if line=='':
            break

        infix = str2infix(line)
        posfix = infix2posfix(infix)
        # print infix
        # print posfix
        print calculate(posfix)[0]
        # break
except:
    pass

优秀解析

1. Python一行代码(py2,py3)

# python2
print(int(eval(raw_input().replace("{","(").replace("}",")").replace("[","(").replace("]",")"))))
# python3
print(int(eval(input().replace("{","(").replace("}",")").replace("[","(").replace("]",")"))))

说明:
eval字符串参数合法的字符包括”+, -, *, /, (, )”,”0-9”(没有“[]”,”{}“)

所以下面的仅仅是处理带小括号的 表达式求值。同时上面也仅仅是把大、中括号替换为小括号

# python2
print(eval(raw_input()))
# python3
print(eval(input()))

2. 传统方法,计算中缀表达式(java)

传统方法,直接通过两个栈,计算中缀表达式的值

import java.util.*;
public class Main{
    // 用于存放一个正括号的集合, 用于简化代码
    static Set<Character> brace = new HashSet<>();
    public static void main(String ... args){
        Scanner sc = new Scanner(System.in);
        // 初始化正括号集合
        brace.add('{');
        brace.add('(');
        brace.add('[');
        while(sc.hasNextLine()){
            // 对字符串做初始化处理,原则有二:
            // 1、处理负数,这里在-前面的位置加入一个0,如-4变为0-4,
            // 细节:注意-开头的地方前面一定不能是数字或者反括号,如9-0,(3-4)-5,这里地方是不能加0的
            // 它的后面可以是数字或者正括号,如-9=>0-9, -(3*3)=>0-(3*3)
            // 2、处理字符串,在最后的位置加#, 主要是为了防止最后一个整数无法处理的问题
            String exp = sc.nextLine().replaceAll("(?<![0-9)}\\]])(?=-[0-9({\\[])", "0") + "#";
            System.out.println(calculate(exp));
        }
    }
    private static int calculate(String exp){
        // 初始化栈
        Stack<Integer> opStack = new Stack<>();
        Stack<Character> otStack = new Stack<>();
         
        // 整数记录器
        String num = "";
        for(int i = 0; i < exp.length(); i++){
            // 抽取字符
            char c = exp.charAt(i);
            // 如果字符是数字,则加这个数字累加到num后面
            if(Character.isDigit(c)){
                num += c;
            }
            // 如果不是数字
            else{
                // 如果有字符串被记录,则操作数入栈,并清空
                if(!num.isEmpty()){
                    int n = Integer.parseInt(num);
                    num = "";
                    opStack.push(n);
                }
                // 如果遇上了终结符则退出
                if(c == '#')
                    break;
                // 如果遇上了+-
                else if(c == '+' || c == '-'){
                    // 空栈或者操作符栈顶遇到正括号,则入栈
                    if(otStack.isEmpty() || brace.contains(otStack.peek())){
                        otStack.push(c);
                    } else {
                        // 否则一直做弹栈计算,直到空或者遇到正括号为止,最后入栈
                        while(!otStack.isEmpty() && !brace.contains(otStack.peek()))
                            popAndCal(opStack, otStack);
                        otStack.push(c);
                    }
                }
                // 如果遇上*/
                else if(c == '*' || c == '/'){
                    // 空栈或者遇到操作符栈顶是括号,或者遇到优先级低的运算符,则入栈
                    if(otStack.isEmpty()
                            || brace.contains(otStack.peek())
                            || otStack.peek() == '+' || otStack.peek() == '-'){
                        otStack.push(c);
                    }else{
                        // 否则遇到*或/则一直做弹栈计算,直到栈顶是优先级比自己低的符号,最后入栈
                        while(!otStack.isEmpty()
                                && otStack.peek() != '+' && otStack.peek() != '-'
                                && !brace.contains(otStack.peek()))
                            popAndCal(opStack, otStack);
                        otStack.push(c);
                    }
                } else {
                    // 如果是正括号就压栈
                    if(brace.contains(c))
                        otStack.push(c);
                    else{
                        // 反括号就一直做弹栈计算,直到遇到正括号为止
                        char r = getBrace(c);
                        while(otStack.peek() != r){
                            popAndCal(opStack, otStack);
                        }
                        // 最后弹出正括号
                        otStack.pop();
                    }
                }
            }
        }
        // 将剩下的计算完,直到运算符栈为空
        while(!otStack.isEmpty())
            popAndCal(opStack, otStack);
        // 返回结果
        return opStack.pop();
    }
    private static void popAndCal(Stack<Integer> opStack, Stack<Character> otStack){
        int op2 = opStack.pop();
        int op1 = opStack.pop();
        char ot = otStack.pop();
        int res = 0;
        switch(ot){
            case '+':
                res = op1 + op2;
                break;
            case '-':
                res = op1 - op2;
                break;
            case '*':
                res = op1 * op2;
                break;
            case '/':
                res = op1 / op2;
                break;
        }
        opStack.push(res);
    }
    private static char getBrace(char brace){
        switch(brace){
            case ')':
                return '(';
            case ']':
                return '[';
            case '}':
                return '{';
        }
        return '#';
    }
}

3. 中缀字符串转变为后缀字符串数组并求解(c++)

//思路:
//1.字符串预处理,针对可能出现的“{,},[,],-”等特殊情况进行替换,判断‘-’是负号还是减号,负号前面+0,转变成减法运算
//2.将中缀字符串转变为后缀字符串数组
//3.对后缀字符串数组进行求解
#include<iostream>
#include<vector>
#include<string>
#include<stack>
#include<sstream>
using namespace std;
bool cmpPriority(char top,char cur)//比较当前字符与栈顶字符的优先级,若栈顶高,返回true
{
    if((top=='+' || top=='-') && (cur=='+' || cur=='-'))
        return true;
 if((top=='*' || top=='/') && (cur=='+' || cur=='-'|| top=='*' || top=='/'))
        return true;
    if(cur==')')
        return true;
    return false;
}
void preProcess(string &str)//对字符串进行预处理
{
    for(int i=0;i<str.size();++i)
    {
        if(str[i]=='{')//将‘{、}、[,]’替换成'()'
            str[i]='(';
        else if(str[i]=='}')
            str[i]=')';
        else if(str[i]=='[')
            str[i]='(';
        else if(str[i]==']')
            str[i]=')';
        else if(str[i]=='-')
        {
            if(i==0)//将'-'前面添加0转变成减法运算
                str.insert(0,1,'0');
            else if(str[i-1]=='(')
                str.insert(i,1,'0');
  }
 }
}
vector<string> mid2post(string &str)
{
    vector<string>vstr;
    stack<char>cstack;
    for(int i=0;i<str.size();++i)//扫描字符串
    {
        string temp="";
        if(str[i]>='0' && str[i]<='9')//若是数字
        {
            temp+=str[i];
            while(i+1<str.size() && str[i+1]>='0' && str[i+1]<='9')
            {
                temp+=str[i+1];//若是连续数字
                ++i;
   }
            vstr.push_back(temp);
  }
        else if(cstack.empty() || str[i]=='(')//若栈空或者字符为'('
            cstack.push(str[i]);
        else if(cmpPriority(cstack.top(),str[i]))//若栈顶元素优先级较高,栈顶元素出栈
        {
            if(str[i]==')')//若当前字符是右括号,栈中元素出栈,入字符串数组中,直到遇到'('
            {
                while(!cstack.empty() && cstack.top()!='(')
                {
                    temp+=cstack.top();
                    cstack.pop();
                    vstr.push_back(temp);
                    temp="";
                }
                cstack.pop();                   
            }
            else//栈中优先级高的元素出栈,入字符串数组,直到优先级低于当前字符
            {
                while(!cstack.empty() && cmpPriority(cstack.top(),str[i]))
                {
                    temp+=cstack.top();
                    cstack.pop();
                    vstr.push_back(temp);
                    temp="";
                }
                cstack.push(str[i]);
   }
        }
        else//当前字符优先级高于栈顶元素,直接入栈
         cstack.push(str[i]);
    }
    while(!cstack.empty())//栈中还存在运算符时,出栈,存入字符串数组
    {
        string temp="";
        temp+=cstack.top();
        cstack.pop();
        vstr.push_back(temp);
    }
    return vstr;
}
int calcPostExp(vector<string> & vstr)//对后缀表达式进行求值,主要是根据运算符取出两个操作数进行运算
{
    int num,op1,op2;
    stack<int>opstack;
    for(int i=0;i<vstr.size();++i)
    {
        string temp=vstr[i];
        if(temp[0]>='0' && temp[0]<='9')//如果当前字符串是数字,利用字符串流转化为int型
        {
            stringstream ss;
            ss<<temp;
            ss>>num;
            opstack.push(num);
        }
        else if(vstr[i]=="+")//若是操作符,取出两个操作数,进行运算,并将结果存入
        {
            op2=opstack.top();
            opstack.pop();
            op1=opstack.top();
            opstack.pop();
            opstack.push(op1+op2);
        }
        else if(vstr[i]=="-")
        {
            op2=opstack.top();
            opstack.pop();
            op1=opstack.top();
            opstack.pop();
            opstack.push(op1-op2);
        }
        else if(vstr[i]=="*")
        {
            op2=opstack.top();
            opstack.pop();
            op1=opstack.top();
            opstack.pop();
            opstack.push(op1*op2);
        }
        else if(vstr[i]=="/")
        {
            op2=opstack.top();
            opstack.pop();
            op1=opstack.top();
            opstack.pop();
            opstack.push(op1/op2);
        }
    }
    return opstack.top();//最终的栈顶元素就是求解的结果
}
void calcExp(string str)
{
    vector<string>vstr;
    preProcess(str);//对字符串进行预处理
    vstr=mid2post(str);//将中缀表达式转为后缀,保存在字符串数组中,方便下一步求解
    int res=calcPostExp(vstr);
    cout<<res<<endl;
}
int main()
{
    string str;
    while(getline(cin,str))
    {
        calcExp(str);
 }
    return 0;
}

3. 统一小括号,中缀表达式转后缀并求解(c++)

思路是很正常的思路

  1. 先把中括号和大括号换成小括号,方便后续处理

  2. 四则运算:中缀表达式转后缀表达式,中途计算算出后缀表达式结果

#include<iostream>
#include<string>
#include<stack>//栈头文件
using namespace std;
string change_bracket(string exp);//将大括号和中括号转成小括号,同时,将负数x转成0-x的形式
int mid_to_post(string exp);
int calculate(int a, int b, char sym);
int main()
{
    string exp;
    while (cin >> exp)
    {
        exp = change_bracket(exp);
        int exp_post = mid_to_post(exp);
        cout << exp_post << endl;
    }
    return 0;
}
//把大括号和中括号换成小括号,以便减少后期过多的判断
string change_bracket(string exp)
{
    for (int i = 0; i < exp.size(); i++)
    {
        if (exp[i] == '{' || exp[i] == '[')
            exp[i] = '(';
        if (exp[i] == '}' || exp[i] == ']')
            exp[i] = ')';
    }
     
    //cout << exp;
    return exp;
}
int mid_to_post(string exp)
{
    int flag = 0;//正负号标志,0为无正负号,1为正号,2为负号
    stack<int> exp_post;//数字栈
    stack<char> symbol;//符号栈
    for (int i = 0; i < exp.size(); i++)
    {
        char temp;
        if (isdigit(exp[i]))//为数字时
        {
            int j = i,num=0;
            while (i + 1 < exp.length() && isdigit(exp[i + 1])) i++;
            string str_num = exp.substr(j, i - j+1);
            for (int k = 0; k < str_num.size(); k++)
                num = num * 10 + str_num[k] - '0';
            if (flag == 2)
                num = 0 - num;
            flag = 0;
            exp_post.push(num);
        }  
        else if (exp[i] == '*' || exp[i] == '/' || exp[i] == '(')//为乘除时
            symbol.push(exp[i]);
        else if (exp[i] == '+'||exp[i] == '-')//为加减时
        {
            /*处理负号先*/
            if (!i || exp[i - 1]=='(')
                if (exp[i] == '+')
                    flag = 1;
                else
                    flag = 2;
 
            /*处理负号先_end*/
            while (!flag&&!symbol.empty() && symbol.top() != '(')//堆栈非空时,符号栈弹出符号,并结合数字栈计算
            {
                int b = 0, a = 0;
                char sym_temp;
                b = exp_post.top();
                exp_post.pop();
                a = exp_post.top();
                exp_post.pop();
                sym_temp = symbol.top();
                symbol.pop();
                exp_post.push(calculate(a, b, sym_temp));//计算结果入栈
            }
            if(!flag) symbol.push(exp[i]);
        }
        else if (exp[i] == ')')//为右括号时
        {
            while (symbol.top() != '(')
            {
                int b = 0, a = 0;
                char sym_temp;
                b = exp_post.top();
                exp_post.pop();
                a = exp_post.top();
                exp_post.pop();
                sym_temp = symbol.top();
                symbol.pop();
                exp_post.push(calculate(a, b, sym_temp));//计算结果入栈
            }
            symbol.pop();
        }
        else
            cout << "Input error!!!" << endl;
    }
    //循环结束后把剩下的符号弹出,并结合数字栈计算
    while (!symbol.empty())
    {
        int b = 0, a = 0;
        char sym_temp;
        b = exp_post.top();
        exp_post.pop();
        a = exp_post.top();
        exp_post.pop();
        sym_temp = symbol.top();
        symbol.pop();
        exp_post.push(calculate(a, b, sym_temp));//计算结果入栈
    }
    return exp_post.top();
}
 
int calculate(int a,int b,char sym)
{
    switch (sym)
    {
        case '+': return a + b;
        case '-': return a - b;
        case '*': return a * b;
        case '/': return a / b;
    default:
        return 0;
        break;
    }
}

参考

  1. 简单算术表达式求值 https://blog.csdn.net/dnxbjyj/article/details/71248637

  2. 首页 > 试题广场 > 四则运算 https://www.nowcoder.com/questionTerminal/9999764a61484d819056f807d2a91f1e

posted @ 2020-03-23 23:45  oucbl  阅读(810)  评论(0编辑  收藏  举报