题目重点:解析非负整数的加法、乘法和幂,合并只含加乘的简化版本并明确语法。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 训练ASCII非负整数、+ * ^、空白,优先级^>* >+,^右结合,0^0=1;不含括号/一元符号/减除。加乘版只用此语法子集。
- power字面运算符与结合性未明确,因此当前^和右结合是训练约定,实际接口需确认。
解题路线
- 递归下降expr=term(+term)*,term=power(*power)*,power=number(^power)?。加乘循环左结合,power递归右侧形成右结合。
- number逐ASCII digit构整数,允许token间空白但不能直接去掉所有空白再拼字符串:1 2是两个不合法相邻操作数,不应变12。
- term完整计算乘法再交expr加法,自然实现优先级;5+2*4得13,不用逐左算成28。^调用自身让2^3^2是2^(3^2)。
- 解析结束必须消耗全文,非法字符/缺operand报错;不得eval用户输入。测试仅对程序生成可信表达式用独立Python算术oracle。
- 幂可制造很大整数,未给约束不能声称无穷可安全计算;语法复杂度与结果位数分开,长幂链有递归深度风险。
手动走一遍
5+2*4=13;2^3^2=512而(2^3)^2=64;1 2、1+、−1、括号都不属本合同应拒绝。幂符号^在Python是XOR,但本解析器把它定义为幂。
Python 参考实现
下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。
代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。
def calculate(text):
"""Training: nonnegative ASCII integer operands, + * ^, whitespace.
No parentheses, unary signs, subtraction or division.
Precedence ^ > * > +; ^ right associative; 0^0=1.
"""
index=0
def skip():
nonlocal index
while index<len(text) and text[index].isspace():index+=1
def number():
nonlocal index
skip();start=index;value=0
while index<len(text) and '0'<=text[index]<='9':
value=value*10+ord(text[index])-ord('0');index+=1
if index==start:raise ValueError('integer operand expected')
return value
def power():
nonlocal index
value=number();skip()
if index<len(text) and text[index]=='^':
index+=1;value=value**power()
return value
def term():
nonlocal index
value=power();skip()
while index<len(text) and text[index]=='*':
index+=1;value*=power();skip()
return value
result=term();skip()
while index<len(text) and text[index]=='+':
index+=1;result+=term();skip()
if index!=len(text):raise ValueError('unexpected token')
return result
复杂度
O(T)token解析工作,加大整数乘法/幂的实际位复杂度;递归stack O(幂链长度)。若只+/*,可用累计term的O(1)语法状态,但当前幂扩展不能直接标常数辅助。
易错点与追问
容易失分的边界
- 去掉全部空白把非法相邻数字拼成合法数。
- 幂左结合改变结果。
- Python ^当幂调用会实际执行XOR。
继续深挖
- 增加括号时number层可扩成primary,但需要匹配闭括号和深度预算。
- 如何限制指数/结果位数保护资源?错误应在接口合同中明确。
