二叉树 树 - 问题集合
二叉树 && 树 - 问题集合
- DFS解决二叉树类问题总体思路
- 寻找公共祖先问题
- 问题 1 :最深叶节点的最近公共祖先
- 步骤 1 :以小问题为例进行思考
- 步骤 2 :扩展成大问题
- 实现
DFS解决二叉树类问题总体思路
DFS解决二叉树问题,本质上是一个小问题嵌套一个小问题,所有小问题组成大问题,每个问题的解决方案一致。
所以在思考的时候,一定不要被题目复杂给迷惑了:
一定要从最简单的二叉树样例开始思考:
1、是从下往上回溯处理,逐层返回信息;
2、还是从上往下逐层处理
只要想通小问题的解决办法,并将之成功扩展成大问题的解决方案,二叉树问题轻松解决
寻找公共祖先问题
寻找公共祖先问题,最简单的思路,记住:
使用回溯法,从下到上处理,逐层返回可能是公共祖先的节点信息。
问题 1 :最深叶节点的最近公共祖先
我们以为力扣1123. 最深叶节点的最近公共祖先例对该问题进行讲解。
步骤 1 :以小问题为例进行思考
我们用如下的例子进行思考:因为题干中还要求我们找的是最深叶节点的公共祖先,所以要带上深度信息
1:
只有一个节点,两个子节点都是空,我们认为深度都==0,此时节点1是两个空节点的公共祖先.
2:
按照上面的思路,此时2、3分别是各自子树的最近公共祖先,深度各自为1
在节点1看来,左侧右侧深度都是1,都是当前位置最大深度叶子节点,所以此时公共祖先就是1
节点1将自己的信息上报,并将深度+1
3:
此时在1看来,左侧深度1,右侧深度0,所以:
1、节点1不可能是公共祖先,因为其右侧子树压根没东西,公共祖先参与的子节点数>=2
2、所以节点1只能是维持左侧子树上传来的结果
3、并将此时深度+1继续上报
4、同“3”中描述,节点1维持右侧上报消息,并将深度+1
步骤 2 :扩展成大问题
1)我们将上述信息进行扩展,针对任意一个节点:
1、他发现左侧子树上报的深度==右侧子树,说明这个子树的最深叶子节点公共祖先是它本身,他将自己上报,并深度++
2、他发现左侧子树上报的深度 > 右侧子树,说明这个左子树才拥有当前子树的最深叶子节点,公共祖先肯定在他们那
所以维持左侧原判,并深度++
3、他发现左侧子树上报的深度 < 右侧子树,说明这个右子树才拥有当前子树的最深叶子节点,公共祖先肯定在他们那
所以维持右侧原判,并深度++
2)根据题中要求,我们不难发现,我们需要返回的信息中,同时包括:深度+节点信息,所以返回:
pair<int,TreeNode*>
实现
class Solution {
public:
pair<int,TreeNode*> find(TreeNode* root) {
if (root == nullptr) {//当遇到空节点,此时深度=0,返回空节点
return { 0,nullptr };
}
//先往左右走再判断,是回溯思路,也就是从下往上,一层层返回目标节点
auto left = find(root->left);
auto right = find(root->right);
//子节点的深度相同,会首先返回自己
//当走到非子结点时,我们要的是最深叶节点的最近公共祖先,哪边深返回哪边,一样的话返回中间
if (left.first == right.first) {
return { left.first + 1,root };
}
if (left.first < right.first) {
return { right.first + 1,right.second };
}
return { left.first + 1,left.second };
}
TreeNode* lcaDeepestLeaves(TreeNode* root) {
return find(root).second;
}
};