[31]逆波兰表达式求值和多数元素

*内容来自leetcode

1.逆波兰表达式求值

题目要求

给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。

请你计算该表达式。返回一个表示表达式值的整数。

注意:

有效的算符为 '+'、'-'、'*' 和 '/' 。
每个操作数(运算对象)都可以是一个整数或者另一个表达式。
两个整数之间的除法总是 向零截断 。
表达式中不含除零运算。
输入是一个根据逆波兰表示法表示的算术表达式。
答案及所有中间计算结果可以用 32 位 整数表示。

示例 1:

输入:tokens = ["2","1","+","3","*"]
输出:9
解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9

示例 2:

输入:tokens = ["4","13","5","/","+"]
输出:6
解释:该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6

逆波兰表达式:

逆波兰表达式是一种后缀表达式,所谓后缀就是指算符写在后面。

平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ) 。
该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。
逆波兰表达式主要有以下两个优点:

去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中

思路

这道题的思路来自于上述,用栈来实现运算。

踩坑的地方有:如何判断原始字符串中的每一个字符是不是数字,最开始用是否大于等于0小于等于9和s.isdigit()判断,但是这两种方法只能无法判断非负的数。引入了异常处理来解决。

另一个就是python负数整除的一个问题,比如6//-132,在python中得到的结果是-1,而非0。所以在进行除法时需要一些额外的操作。

class Solution:
    def evalRPN(self, tokens: List[str]) -> int:
        # 判断是否为数字
        def is_number(s):    
            try:    # 如果能运⾏ float(s) 语句,返回 True(字符串 s 是浮点数)        
                float(s)        
                return True    
            except ValueError:  # ValueError 为 Python 的⼀种标准异常,表⽰"传⼊⽆效的参数"        
                pass  # 如果引发了 ValueError 这种异常,不做任何事情(pass:不做任何事情,⼀般⽤做占位语句)    
            #try:        
            #    import unicodedata  # 处理 ASCII 码的包        
            #    unicodedata.numeric(s)  # 把⼀个表⽰数字的字符串转换为浮点数返回的函数        
            #    return True    
            #except (TypeError, ValueError):        
            #    pass    
            #    return False
        num = []
        method = []
        for element in tokens:
            if is_number(element):#
                num.append(int(element))
            else:
                num2 = num.pop()
                num1 = num.pop()
                flag = 1
                if num1 < 0:
                    flag = -flag
                if num2 < 0 :
                    flag = -flag

                if element == '+':
                    num.append(num1 + num2)
                if element == '-':
                    num.append(num1 - num2)
                if element == '*':
                    num.append(num1 * num2)
                if element == '/':
                    num2 = abs(num2)
                    num1 = abs(num1)
                    num.append(num1 // num2 * flag)
        return num.pop()

提供一个更为简洁的写法。官方的题解中,一种使用栈来实现,一种是用数组,对于python来说这两种区别不大,写法上有些区别,就不再重复。

class Solution:
    def evalRPN(self, tokens: List[str]) -> int:
        op_to_binary_fn = {
            "+": add,
            "-": sub,
            "*": mul,
            "/": lambda x, y: int(x / y),   # 需要注意 python 中负数除法的表现与题目不一致
        }

        stack = list()
        for token in tokens:
            try:
                num = int(token)
            except ValueError:
                num2 = stack.pop()
                num1 = stack.pop()
                num = op_to_binary_fn[token](num1, num2)
            finally:
                stack.append(num)
            
        return stack[0]

2.多数元素

题目要求

给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

示例 1:

输入:nums = [3,2,3]
输出:3
示例 2:

输入:nums = [2,2,1,1,1,2,2]
输出:2

思路

好像做过类似的。

第一个数进栈,如果下一个数相同则继续入栈,不同则出栈一个数

class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        stk = []
        for i in range(len(nums)):
            if not stk or nums[i] == stk[-1]:
                stk.append(nums[i])
            else:
                stk.pop()
        return stk[-1]

官方归纳了5种解法,哈希表、排序寻找中位数、随机读取、分治和Boyer-Moore 投票算法。其中最后一种算法的思路跟我写的这个差不多,只不过具体实现不同。接下来分别列出几种解法。

class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        #哈希表
        newMap = {}
        maxNum = 0
        res = 0
        for element in nums:
            if not newMap.get(element):
                newMap[element] = 1
            else:
                newMap[element] += 1
            if newMap[element] > maxNum:
                maxNum = newMap[element]
                res = element

        return res
class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        #排序后找中位数
        nums.sort()
        return nums[len(nums)//2]
class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        #随机读取
        half_count = len(nums) // 2
        
        while True:
            randomNum = random.choice(nums)
            if sum(1 for count in nums if count == randomNum) > half_count:
                return randomNum
class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        #分治
        def findMode(nums):
            if len(nums) == 1:
                return nums[0]
            mid = len(nums) // 2
            leftMode = findMode(nums[:mid])
            rightMode = findMode(nums[mid:])
            if leftMode == rightMode:
                return leftMode
            if sum(1 for element in nums if element == leftMode) > sum(1 for element in nums if element == rightMode):
                return leftMode
            else:
                return rightMode
        return findMode(nums)
class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        #Boyer-Moore 算法,来自官方
        count = 0
        candidate = None

        for num in nums:
            if count == 0:
                candidate = num
            count += (1 if num == candidate else -1)

        return candidate

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值