[leetcode 224 & 227]Basic Calculator I & II 原创解法
题目概述
Implement a basic calculator to evaluate a simple expression string.
这两道题可以使用一种通用的解法来解。所以就放在一起了。
"1 + 1" = 2
" 2-1 + 2 " = 3
"(1+(4+5+2)-3)+(6+8)" = 23
"3+2*2" = 7
" 3/2 " = 1
" 3+5 / 2 " = 5
波兰计数法
波兰计数法
是一种非常巧妙的方法,只使用一个栈结构就能计算表达式。
但是呢,我们常用的表达式是一种infix
表达式,而波兰计数法
是一种
postfix
表达式。所以需要一种把infix expression
转换成postfix expression
。转换方法
抽象语法树
我还是想用抽象语法树的形式来解。也就是说先把表达式转换成一棵二叉树。
然后再计算这棵树。思路很简单,所以呢,为了直观的看到树状结构。
我发现Python
下有一个不错的包binarytree
,这个包可以打印树状图。
我们先来看看打印的结果吧。是不是很不错。
0-(1+2)*3*(4-3/5/5)+1+1
__+
/ \
__________________________+ 1
/ \
-__________ 1
/ \
0 __*__
/ \
__* -______
/ \ / \
+ 3 4 __/
/ \ / \
1 2 / 5
/ \
3 5
初步解法
根据以上的思路,我们首先定义一个Tree
,继承自binarytree
的Node
。
然后就先对字符串处理成token
流,其实这题没这个要求。简单的去掉
空格就行了。也没有复杂的数字。下面给出了生成AST
的初步代码。
算是递归下降法吧。
然后再计算树的值。
1 |
|
栈调用过深了
以上的解法中生成语法树的过程因为使用了多个递归,结果调用的栈过深,结果 出错了。因为 python默认的递归栈深度是10000。
RecursionError: maximum recursion depth exceeded while calling a Python object
怎么办呢,想办法把递归改成非递归吧。但是看了又看还是没有发现如何改,
因为存在两个函数相互调用的嵌套递归。不管怎样,先减少一个递归函数吧。
去掉了parse_term
函数。
1 |
|
居然不出现栈溢出了。呵呵。(其实还是存在这个问题,只是能够通过leetcode测试了)
但是计算的过程TreeNode::compute
还是出现了调用过深的错误RecursionError
。
这个没关系啊,我们可以改成非递归的栈模拟方式
。
1 |
|
通过的代码
1 |
|
总结
虽然代码长了点,但是练习了一下如何生成一个抽象语法树
。并且练习了
如何把一个调用自身的递归改成非递归。
[leetcode 224 & 227]Basic Calculator I & II 原创解法
https://threelambda.com/2016/10/24/leetcode-224/