利用二叉树求解表达式的值_「力扣题型总结」匹配类二叉树

38ad4af59bc73715a145bd11fb1da901.png

匹配类二叉树可以使用一种套路相对固定的递归函数,在周赛中和每日一题中多次出现,而第一次见到不太容易写出正确的递归解法,因此我们来总结一下。(注:不要太纠结于名字,因为名字是我自己起的......)

这类题目与字符串匹配有些神似,求解过程大致分为两步:

  • 先将根节点匹配;
  • 根节点匹配后,对子树进行匹配。

而参与匹配的二叉树可以是一棵,与自身匹配;也可以是两棵,即互相匹配。

比如每日一题的「101. 对称二叉树」就是两棵树之间的匹配问题。为了更具一般性,我们先来看「面试题 04.10. 检查子树」这道题。

面试题 04.10. 检查子树

这道题的题意是这样的:输入两棵二叉树 AB,判断 B 是不是 A 的子结构,且约定空树不是任意一个树的子结构。

2205ccda8a8a52a6e9dac86f8f99d266.png

比如上面这个例子,我们发现 BA 的子结构,因为它们的结构相同,且节点值相等。

求解思路可以分解为以下两步:

  1. 匹配根节点:首先在 A 中找到与 B 的根节点匹配的节点 C
  2. 匹配其他节点:验证 C 的子树与 B 的子树是否匹配。

最终代码如下:

3f0a2476f9a8002416d9a893afaed278.png

代码中主要涉及 主函数和 dfs 函数 两个部分。与以上思路对应,主函数对应根节点的匹配,dfs 函数对应匹配其他节点。

dfs 函数

dfs 函数将注意力集中在了根节点已经匹配的情况。当从根节点同时开始向下遍历时,我们进行以下判断:

  1. 如果 AB 同时遍历到了 null,说明匹配成功,返回 True(case 1 红色虚线框);
  2. 如果 AB 提前遍历到了 null,一棵树匹配完了,另一棵却没有,说明子树的结构是不同的,则匹配失败,返回 False(case 2 红色虚线框)。

d663a29cbd261db36386fb6fba7c064b.png

以上是“基本情况”,在到达基本情况之前,我们需要判断根节点的值、左子树(调用递归)和右子树(调用递归)是否匹配。

于是就有了代码中的 dfs 函数形式:

a7af55e7f732ef0eee7174970912b054.png

主函数

现在将视野放远来看,主函数则解决了如何确定 A 的哪个节点是 B 的根节点

如果 A 的当前节点值与 B 的根节点值相同,我们调用 dfs 函数判断子树是否也相同;如果不同,我们就递归调用主函数来寻找 A 的哪个节点与 B 的根节点匹配。

所以,主函数会写成这样:

596356bf80e8eba52e6b681296768dba.png

当然,主函数还经常需要判断以下边界条件,比如如果 A 为空,则肯定不匹配,返回 False

总结

熟悉了以上的思路之后,力扣很多类似的题目都可以使用题目中的代码解决。

这些题目中,可能会有自身和自身做匹配的,比如每日一题「101. 对称二叉树」,将自身看作两棵树,用左子树和右子树镜像比较;

可能会将另一棵树变成一个链表,比如「1367. 二叉树中的列表」,仍然是先将链表头部与二叉树的某个节点匹配,再验证后续是否匹配;

也可能像「面试题26. 树的子结构」这样,前面的例题很像,不同的是 B 属于 A 的一部分也可以,没必要一直匹配到叶子节点;

还有与例题相同思路的「572. 另一个树的子树」

......


算法与技术面试​zhuanlan.zhihu.com
599e45270d7c23cd8852db8cc6d1122d.png
腐烂的橘子:旋转数组的通用解决办法​zhuanlan.zhihu.com
24e769bfc5ef87d5d8ab8e2e1f22debb.png
利用二叉树求解表达式有以下步骤: 1. 将中缀表达式转换为后缀表达式; 2. 通过后缀表达式构建表达式二叉树; 3. 通过递归遍历表达式二叉树计算表达式。 具体实现方法如下: 1. 将中缀表达式转换为后缀表达式 例如,将中缀表达式 3+4*5 转换为后缀表达式 345*+ 转换的步骤如下: 1. 从左至右扫描中缀表达式; 2. 若读取的是数字,则直接输出; 3. 若读取的是运算符,则判断其与栈顶运算符的优先级,是右括号或优先级低于栈顶运算符则栈顶运算符弹出并输出,直到优先级高于栈顶运算符或栈空,然后将该运算符压入栈中; 4. 若读取的是左括号,则将其压入栈中; 5. 若读取的是右括号,则依次弹出栈顶运算符并输出,直到遇到左括号,左括号弹出但不输出。 2. 通过后缀表达式构建表达式二叉树 例如,对于后缀表达式 345*+,构建的表达式二叉树如下: ``` + / \ 3 * / \ 4 5 ``` 构建的步骤如下: 1. 从左至右扫描后缀表达式; 2. 若读取的是数字,则创建一个新节点,为该数字,并将其压入栈中; 3. 若读取的是运算符,则创建一个新节点,为该运算符,然后从栈中弹出两个节点作为该节点的左右子节点,将该节点压入栈中; 4. 重复步骤1-3,直到遍历完整个后缀表达式,此时栈中只剩下一个节点,即为根节点。 3. 通过递归遍历表达式二叉树计算表达式 例如,对于构建的表达式二叉树,通过递归遍历计算表达式如下: 1. 计算左子树的; 2. 计算右子树的; 3. 根据根节点的运算符,计算左右子树的的结果; 4. 返回结果。 对于以上表达式二叉树,遍历的顺序为先遍历左子树,再遍历右子树,最后计算根节点的,计算过程如下: 1. 遍历左子树,计算 3 的,返回 3; 2. 遍历右子树,先遍历左子树,计算 4 的,返回 4,再遍历右子树,计算 5 的,返回 5,最后计算乘法运算符的结果,即 4*5=20,返回 20; 3. 计算加法运算符的结果,即 3+20=23,返回 23。 因此,表达式 3+4*5 的为 23。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值