[編程題] 四則運算


[編程題] 四則運算

題目描述

請實現如下接口

/* 功能:四則運算
* 輸入: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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM