224.基本计算器

224.基本计算器

难度 困难

题目

给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。

示例1

输入:s = “1 + 1”
输出:2

示例2

输入:s = " 2-1 + 2 "
输出:3

示例3

输入:s = “(1+(4+5+2)-3)+(6+8)”
输出:23

提示

  • 1 <= s.length <= 3 * 105
  • s 由数字、’+’、’-’、’(’、’)’、和 ’ ’ 组成
  • s 表示一个有效的表达式
解题思路—双栈

遇到计算器问题就用两个栈来解决问题,一个数字栈(用来存数字),一个运算符栈(用来存运算符),同时,要定义运算符优先级。然后遍历字符串,分情况讨论:

  • 遇到数字就直接存入数字栈(这其中还要对大于10的数进行处理)
  • 对于遇到括号
  1. 遇到左括号就直接存入运算符栈
  2. 遇到右括号就取出数字栈顶两个数,取出运算符栈顶一个运算符进行计算,直到遇到左括号为止,计算完到最后记得删除左括号
  • 遇到非括号的一般运算符,则要比较当前运算符与上一个运算符的优先级,只有上一个运算符的优先级大于当前运算符的优先级时,才进行计算(对上一个运算符和栈顶两个数进行计算,计算完后将计算结果存入数字栈,再将当前运算符存入运算符栈)。否则,直接将当前运算符存入运算符栈
    举个🌰
    ‘2+3*6-1’,应该先计算 3 * 6,再计算2 + 18 - 1。我们按照解题思路将‘2’存入数字栈,将‘+’存入运算符栈,接下来‘3’存入数字栈,则此时 num_stack:[2 3],op_stack:[+]。接下来遇到了‘*’,其上一个运算符为‘+’,上一个运算符优先级小于当前运算符优先级,则直接将‘*’入栈。不然要是进行计算的话,则就先计算2+3了,这样就错了。然后接下来‘6’入数字栈, num_stack:[2 3 6],op_stack:[+ *],接下来遇到‘-’,因为上一个运算符‘*’优先级大于当前运算符‘-’优先级,故进行计算,取出栈顶运算符‘*’和栈顶两个数‘6’和‘3’,计算6*3,并将计算结果18存入数字栈,再将‘-’存入运算符栈,则此时 num_stack:[2 18],op_stack:[+ -],接下来‘1’存入数字栈。哎,等等等等,大家有没有发现一个问题,将字符串最后一个元素‘1’存入数字栈后,字符串遍历结束,但是数字栈和运算符栈中还有元素没有计算,我们最后的结果肯定返回的是数字栈中的唯一剩下的一个数(最终计算结果),但是此刻,数字栈中还有[2 18 1],字符串遍历结束,程序到此终止了。所以为了将所有的数都计算完成,我们在程序开始就对字符串s两边加上括号,这样字符串最后一个元素必为右括号,遇到右括号就会对数字栈中元素进行计算,直到遇到左括号。
代码
class Solution(object):
    def calculate(self, s):
        """
        :type s: str
        :rtype: int
        """
        op_priority = {'+':0, '-':0, '*':1, '/':1, '%':1, '^':2}
        # s一定要两边再加括号,这样才能计算完全,否则最后没有右括号还会少一部分没算
        s = '(' + s.replace(' ', '').replace('(-', '(0-') + ')' 
        n = len(s)
        i = 0
        num_stack, op_stack = [], []
        while i < n:
            c = s[i]
            i += 1
            if c.isdigit():
                num = int(c)
                while i < n and s[i].isdigit():
                    # 防止有大于10的两位数字,即数字与数字之间没有运算符,则是一个大于10的整数
                    num = num * 10 + int(s[i])  
                    i += 1
                num_stack.append(num)
            elif c == '(':
                # 遇到左括号直接进运算符栈
                op_stack.append(c)  
            elif c == ')':
                # 遇到右括号则要进行计算,直到遇到左括号结束(对括号内数字运算)
                while op_stack and op_stack[-1] != '(':
                    self.calc(num_stack, op_stack)
                op_stack.pop()  # 括号内数字计算完成,要删除左括号 
            else:
                # 普通运算符要进行优先级比较,当上一个运算符优先级大于当前运算符时,才进行计算(对上一个运算符计算),然后再将当前运算符加入栈;反之,直接将当前运算符加入栈即可
                while op_stack and op_stack[-1] != '(':
                    pre_op = op_stack[-1]
                    if op_priority[pre_op] < op_priority[c]:
                        break
                    else:
                        self.calc(num_stack, op_stack)
                op_stack.append(c)
        return num_stack[0]

    def calc(self, num_stack, op_stack):
        op, y, x = op_stack.pop(), num_stack.pop(), num_stack.pop() if num_stack else 0
        re = 0
        if op == '+':
            re = x + y
        if op == '-':
            re = x - y
        if op == '*':
            re = x * y
        if op == '/':
            re = x / y
        if op == '%':
            re = x % y
        if op == '^':
            re = pow(x, y)
        num_stack.append(int(re))
         

至此,此题解答完毕

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Xamarin.Forms 是一个跨平台开发框架,可用于开发运行在 iOS、Android 和 UWP 等多个平台的应用程序。所以在使用 Xamarin.Forms 开发计算器应用时,我们需要处理计算器的符号问题。 在计算器应用中,常用的计算符号有加法、减法、乘法和除法。我们可以使用 Xamarin.Forms 中的按钮控件来表示这些符号,并为这些按钮添加相应的点击事件处理逻辑。 首先,我们可以创建四个按钮来表示加法、减法、乘法和除法符号。例如,我们可以创建一个按钮来表示加法符号“+”,并在按钮的 Clicked 事件回调中执行加法运算的逻辑。 ```csharp var addButton = new Button { Text = "+" }; addButton.Clicked += (sender, e) => { // 执行加法运算的逻辑 // ... }; ``` 类似地,我们可以为减法、乘法和除法符号分别创建对应的按钮,并为它们的 Clicked 事件回调添加相应的逻辑。 在具体的运算逻辑中,我们可以使用 C# 中的数学运算符来执行相应的计算操作。例如,利用加法运算符进行加法运算,利用减法运算符进行减法运算,以此类推。 通过在 Xamarin.Forms 中创建按钮来表示计算器符号,并在相应的点击事件回调中执行相应的运算逻辑,我们可以实现一个简单的计算器应用,用于处理不同符号的计算操作。 ### 回答2: Xamarin.Forms是一个用于创建跨平台移动应用的工具集。对于计算器符号,我们可以结合Xamarin.Forms的特性和功能来实现。首先,我们可以使用XAML来创建界面布局,然后在代码中添加功能。 对于计算器符号,我们可以使用各种方式来实现。一种常见的方式是使用字体图标库,如FontAwesome或Material Design Icons。这些库提供了各种各样的符号图标,可以通过在XAML中引用设置图标。 另一种方式是使用图片作为符号。我们可以选择符号图片并将其包含在我们的项目中。然后,我们可以在XAML中使用Image控件来显示这些图片符号。 同时,我们还可以使用字符来表示符号。Xamarin.Forms允许在文本控件中使用Unicode字符。我们可以在XAML或代码中直接设置控件的文本属性并使用特定的Unicode字符表示计算器符号。 综上所述,对于Xamarin.Forms的计算器符号,我们可以通过使用字体图标库、图片或Unicode字符来实现。这取决于我们的需求和喜好。无论我们选择哪种方式,Xamarin.Forms都提供了丰富的功能和灵活的选项,使我们能够轻松实现并使用计算器符号。 ### 回答3: 在Xamarin.Forms中实现计算器符号的方法如下: 1. 创建一个Xamarin.Forms项目,选择适当的模板作为起点。 2. 在XAML中设计计算器的界面,包括数字按钮、操作符按钮和结果显示框。 3. 创建一个ViewModel类来处理计算逻辑。可以使用Command模式来处理按钮的点击事件和计算逻辑。 4. 在ViewModel中,使用逻辑运算符和条件语句来实现计算器的功能。例如,可以使用if语句判断输入的操作符是加法、减法、乘法还是除法,并根据不同的操作符执行相应的计算操作。 5. 使用绑定机制将计算结果显示在界面上。可以将结果显示框绑定到ViewModel中的一个属性,当计算结果发生变化时,界面会自动更新。 6. 测试计算器的功能,确保各种操作符都能正确计算结果。 综上所述,通过在Xamarin.Forms中使用ViewModel和绑定机制,我们可以实现一个简单的计算器,可以处理各种运算符号,并将结果展示在界面上。以上方法只是其中一种实现方式,您也可以根据自己的需要和喜好进行调整和修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值