*内容来自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