算法学习(13)表达式问题(利用栈)

1、计算器问题

题目:LeetCode227
给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。
整数除法仅保留整数部分。
你可以假设给定的表达式总是有效的。所有中间结果将在 [-231, 231 - 1] 的范围内。
注意:不允许使用任何将字符串作为数学表达式计算的内置函数,比如 eval() 。
示例:
输入:s = “3+2*2”
输出:7

方法:遍历字符串s,并用变量preSign记录每个数字之前的运算符,每次遍历到数字末尾时,根据该数字之前的运算符preSign来决定计算方式。preSign初始值设为加号:
加号:将数字压入栈;
减号:将数字的相反数压入栈;
乘除号:计算数字与栈顶元素,并将栈顶元素替换为计算结果;
代码实现中,若读到一个运算符,或者遍历到字符串末尾,即认为是遍历到了数字末尾。处理完该数字后,更新preSign为当前遍历的字符。
遍历完字符串s后,将栈中元素累加,即为该字符串表达式的值。

Java代码:

public int calculate(String s) {
    Deque<Integer> stack = new ArrayDeque<Integer>();
    char perSign = '+';
    int num = 0;
    int n = s.length();
    for(int i = 0; i < n; i ++){
        if(Character.isDigit(s.charAt(i))){
            num = num * 10 + s.charAt(i) - '0';
        }
        if( !Character.isDigit(s.charAt(i)) && s.charAt(i) != ' ' || i == n - 1){
            switch(perSign){
                case '+':
                    stack.push(num);
                    break;
                case '-':
                    stack.push(-num);
                    break;
                case '*':
                    stack.push(stack.pop() * num);
                    break;
                default:
                    stack.push(stack.pop() / num);
            }
            perSign = s.charAt(i);
            num = 0;
        }
    }
    int ans = 0;
    while( !stack.isEmpty() ){
        ans += stack.pop();
    }
    return ans;
}

Python代码:

def calculate(self, s):
    n = len(s)
    stack = []
    preSign = '+'
    num = 0
    for i in range(n):
        if s[i] != ' ' and s[i].isdigit():
            num = num * 10 + ord(s[i]) - ord('0')
        if i == n - 1 or s[i] in '+-*/':
            if preSign == '+':
                stack.append(num)
            elif preSign == '-':
                stack.append(-num)
            elif preSign == '*':
                stack.append(stack.pop() * num)
            else:
                #原来python没有自动转成int型数字的功能,必须额外写上
                #我宣布python是最怪的语言,负数取正竟然是向下取整,别的语言不用int型就能直接向上取整
                t = stack.pop()
                if t < 0 and t % num != 0 :
                    stack.append(int(t / num) + 1)
                else:
                    stack.append(int(t / num))
            preSign = s[i]
            num = 0
    return sum(stack)

C++代码:

public:
    int calculate(string s) {
        stack<int> numStack;
        int num = 0;
        char sign = '+';
        for(int i = 0; i < s.length(); i ++){
            char c = s[i];
            if(isdigit(c)){
                num = num * 10 + (c - '0');
            }
            if( !isdigit(c) && c != ' ' || i == s.length() - 1){
                if(sign == '+'){
                    numStack.push(num);
                }
                else if(sign == '-'){
                    numStack.push(-num);
                }
                else if(sign == '*'){
                    //java这样写就行,C++就不行,哎说是'void' and 'int'
                    //numStack.push(numStack.pop() * num); 
                    int prevNum = numStack.top();
                    numStack.pop();
                    numStack.push(prevNum * num);
                }
                else if(sign == '/'){
                    int prevNum = numStack.top();
                    numStack.pop();
                    numStack.push(prevNum / num);
                }
                sign = c;
                num = 0;
            }
        }
        int result = 0;
        while(!numStack.empty()){
            result += numStack.top();
            numStack.pop();
                    
        }
        return result;

    }

2、逆波兰表达式

题目:LeetCode150
给你一个字符串数组 tokens,表示一个根据逆波兰表示法表示的算术表达式。
请你计算该表达式。返回一个表示表达式值的整数。
示例:
输入:tokens = [“2”,“1”,“+”,“3”,“*”]
输出:9
解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9

基础认识:将一般表达式转化成二叉树,使用的是中序遍历。
例如:中缀表达式:1 + (2 + 3) * 4 - 5转化成二叉树为
在这里插入图片描述
根据这个二叉树:
前缀表达式为:- + 1 * + 2 3 4 5
后缀表达式为:1 2 3 + 4 * + 5 -
但对于计算机来说,中缀表达式是很复杂的,因此计算表达式的值时,通常需要先将中缀表达式转化成前缀或后缀表达式再进行求解。
前缀表达式的运算符位于两个相应操作数之前,前缀表达式又被称为前缀记法或波兰式。
后缀表达式与其相反,即逆波兰式。

方法:利用栈,遇见数字即进栈,遇见运算符,则取出栈中最上面的两个元素进行计算,最后将运算结果入栈。

Java代码:

public int evalRPN(String[] tokens) {
    Stack<Integer> stack = new Stack<>();
    //token是字符串
    for(String token : tokens){
        if(!Character.isDigit(token.charAt(0)) && token.length() == 1){
            //运算符,从栈中取出两个数进行运算
            int b = stack.pop();
            int a = stack.pop();
            switch(token){
                //根据运算符的种类进行计算,将结果直接入栈
                case "+": stack.push(a + b); break;
                case "-": stack.push(a - b); break;
                case "*": stack.push(a * b); break;
                case "/": stack.push(a / b); break;
            }
          
        }
        else{
            //整数直接入栈
            stack.push(Integer.parseInt(token));
        }
    }
    return stack.pop();

}

Python代码:

def evalRPN(self, tokens):
    stack = [];
    for token in tokens:
        #运算符,从栈中取出两个树进行运算
        if len(token) == 1 and not token.isdigit():
            b = stack.pop()
            a = stack.pop()

            if token == '+':
                stack.append(a + b)
            elif token == '-':
                stack.append(a - b)
            elif token == '*':
                stack.append(a * b)
            elif token == '/':
                if a % b != 0 and a / b < 0:
                    stack.append(int(a / b) + 1)
                else:
                    stack.append(int(a / b))
        else:
            #整数直接入栈
            stack.append(int(token))
    return stack.pop()

C语言代码:

int evalRPN(char** tokens, int tokensSize) {
    int stack[tokensSize];
    int top = -1;

    for(int i = 0; i < tokensSize; i ++){
        //token应该也是一种数组或字符串
        char* token = tokens[i];

        if(strlen(token) == 1 && !isdigit(token[0])){
            //运算符,从栈中取出两个数经行计算
            int b = stack[top --];
            int a = stack[top --];

            switch(token[0]){
                //根据运算符的种类进行计算,将结果直接入栈
                case '+':
                    stack[++ top] = a + b;
                    break;
                case '-':
                    stack[++ top] = a - b;
                    break;
                case '*':
                    stack[++ top] = a * b;
                    break;
                case '/':
                    stack[++ top] = a / b;
                    break;  
            }
        }
        else{
            //整数直接入栈,atoi是类型转换符吗?
            stack[++ top] = atoi(token);
        }
    }
    return stack[top];
    
}

Python代码(本地编辑器测试代码):

class EvalRPN():
    def evalRPN(self, tokens):
        stack = [];
        for token in tokens:
            #运算符,从栈中取出两个树进行运算
            if len(token) == 1 and not token.isdigit():
                b = stack.pop()
                a = stack.pop()

                if token == '+':
                    stack.append(a + b)
                elif token == '-':
                    stack.append(a - b)
                elif token == '*':
                    stack.append(a * b)
                elif token == '/':
                    stack.append(int(a / b))
                    """
                    这个地方的话是有歧义的,不同版本python规则不一样
                    if a % b != 0 and a / b < 0:
                        stack.append(int(a / b) + 1)
                    else:
                        stack.append(int(a / b))
                    """
            else:
                #整数直接入栈
                stack.append(int(token))
        return stack.pop()

#以下是测试代码:
if __name__ == '__main__':
    tokens = ["10","6","9","3","+","-11","*","/","*","17","+","5","+"]
    solution = EvalRPN()
    result = solution.evalRPN(tokens)
    print("The result is:",result)

本篇文章为原创文,欢迎转载,请注明文章出处https://blog.csdn.net/2301_79084755/article/details/136426642。技术类文章一般都有时效性,本人会不定期对自己的博客进行修正更新,因此请访问出处以查看本文的最新版本。

  • 21
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值