问题描述
试题编号: 201903-2
试题名称: 二十四点
时间限制: 1.0s
内存限制: 512.0MB
问题描述:
解题思路
- 本题是表达式求解问题的简化版。
- 表达式求解通常分成两大步。第一大步是把中缀表达式换成后缀表达式。第二大步是计算后缀表达式,得到结果值。这两大步都会用到堆栈这个数据结构。下面的代码对应的的解法没有包含中缀表达式转换成后缀表达式的步骤。
- 本题的解法核心是:
对每一个表达式,
(1)用一个堆栈存储操作数,这个堆栈叫做操作数堆栈。用另一个堆栈存储操作符,这个堆栈叫做操作符堆栈。一开始,两个堆栈都为空。
(2)从左到右扫描表达式,如果遇到数字,那么把数字存储操作数堆栈。如果遇到操作符O(即非数字),那么看情况处理:
1)如果操作符堆栈中没有任何操作符,那么把操作符O压入操作符堆栈。
2)如果操作符堆栈中已有操作符P,那么执行以下两个步骤:
a)如果操作符P的优先级高于或等于操作符O,则从操作数堆栈尾部取出右操作数和左操作数,从操作符堆栈尾部取出操作符,执行一步四则运算,把运算结果压入操作数堆栈。
b)把操作符O压入堆栈。
(3)扫描完毕后,留在操作符堆栈内的运算符要逐一处理:从操作数堆栈尾部取出右操作数和左操作数,从操作符堆栈尾部取出操作符,执行一步四则运算,把运算结果压入操作数堆栈。
参考答案
# 执行加减乘除运算
def calculate(left, right, operator):
if operator == '+':
return left + right
elif operator == '-':
return left - right
elif operator == 'x':
return left * right
elif operator == '/':
return left // right
# 执行一步计算
# 从nums列表中取出倒数第一个数,作为右操作数,取出倒数第二个数,作为左操作数
# 从operators列表中取出倒数第一个运算符,作为操作符
# 运算结果存入nums列表尾部
def handle_one_step(nums, operators):
right = nums.pop()
left = nums.pop()
op = operators.pop()
nums.append(calculate(left, right, op))
n = int(input())
op_levels = {'+': 1, '-': 1, 'x': 2, '/': 2}
for i in range(n):
nums = []
operators = []
line = input()
for s in line:
if s.isdigit():
nums.append(int(s))
elif len(operators) == 0:
operators.append(s) #第一个运算符
else:
if op_levels[s] > op_levels[operators[-1]]:
operators.append(s) #遇到优先级更高的运算符
else:
handle_one_step(nums, operators) #operators尾部的运算符优先级更高或相等,执行计算
operators.append(s)
# print("nums=", nums, " operators=", operators)
#已经读入整个式子,留在operators内的运算符要逐一处理!!
while len(operators) > 0:
handle_one_step(nums, operators)
# print(nums[0])
if nums[0] == 24:
print('Yes')
else:
print('No')
测试用例
- 题目描述中给出的测试用例已经覆盖了只包含+, -的情形,只包含x, /的情形,先+, -后x, /的情形,先x, /后+, -的情形。根据题目描述的子任务一栏给出的说明可见,n始终等于100,因此无需考虑n=1的边界情形。
小结
- 本题是表达式求解问题的简化版。表达式求解会用到堆栈这个数据结构。在数据结构课程中,讲解堆栈通常会以表达式求解作为案例。吃透并熟练表达式求解问题的算法是值得的。
- 一般的表达式求解问题会涉及后缀表达式。因为题目简化了,本题没有用到后缀表达式。