解题
https://leetcode-cn.com/problems/merge-two-binary-trees/
将两个二叉树合并成一个,相同位置的节点值加和,如果有一个节点位置是空,则相当于该节点值为0。
先复习一下DFS模板
DFS
模板
//父节点要传给子节点值,则放到递归的形参中pass_para。
dfs(TreeNode* root, int pass_para) {
//终止条件
if(root == nullptr) return;
//return放递归上面则会终止到当前节点,不继续向下面子树遍历,不执行后面的语句
//前序遍历:在此添加语句。自顶向下,按照根左右的顺序遍历
//是左子树向当前节点返回的值,这个返回值的定义具体要看当前函数的return是什么
int leftV = dfs(root->left);
//中序遍历:在此添加语句。执行顺序为左根右
int rightV = dfs(root->right);
//后序遍历:在此添加语句。自底向上,按照左右根的顺序
return xxx; //当前节点返回给父节点的值,放在return中。
}
模板解读:
-
root->left = xxx 才是指向,root = root->left是移动指针遍历
-
父节点要传给子节点值,则放到递归的形参中。
void dfs(TreeNode* root, int path)
这里的path是一条路径的值,如果要定义全局的值比如累加所有节点的和那么要放到外面共享变量中。 -
void dfs(TreeNode *root, int pathSum, vector<int>& vPath)
其中vPath是引用,则他是所有节点共享的,所以在返回的时候要pop出去,如果他不是引用,则他是从根节点到叶子节点的每条路径都是一个vPath。具体参考113题 -
return返回的值会把该值返回给父节点,如果是前序遍历return也就是放在dfs上面,则他不继续向下遍历,直接返回给父节点。如果是后续遍历return也就是正常向上返回但是是后续遍历的顺序。
-
int a = dfs(root->left)
是左子树向当前节点返回的值,这个返回值的定义具体要看当前函数的return是什么 -
二叉树的遍历-前序、中序、后序:时间复杂度是多少?答案是:「O(n)」,这里的n代表二叉树里边树的节点的总数,不管是哪种方式遍历,每个节点都有且仅访问一次,所以它的复杂度是线性于二叉树的节点总数,也就是O(n)
拿到返回值不表示重新又走了一次该节点,比如前序遍历,按照根左右的顺序,遍历到某个节点,当前节点拿到的返回值是子节点返回的,也就是说你去算,算完了之后把值给我,也就是说,在代码中间子节点算的时候我等着,值返回给我我再向上返回,但是每个节点该函数只走一次,也就是每个节点只遍历了一次
代码及思路
DFS
//同时前序遍历两个树,判断当前节点情况,相加给到t1,最后我们返回t1树
class Solution
{
public:
TreeNode *mergeTrees(TreeNode *t1, TreeNode *t2)
{
return dfs(t1,t2);
}
TreeNode * dfs(TreeNode *t1, TreeNode *t2) {
//终止条件:如果两个都为null则终止
if(t1 == nullptr && t2 == nullptr) return nullptr;
//其中有一个null则返回另一个
if(t1 == nullptr && t2 != nullptr) return t2;
if(t2 == nullptr && t1 != nullptr) return t1;
//1. 两个都有值我们将两个值相加,加完都给t1
t1->val = t1->val + t2->val;
// 3.当前节点的左子节点接收左子树的返回值
t1->left = dfs(t1->left, t2->left);
t2->right = dfs(t1->right, t2->right);
// 2. 将t1返回给父节点
return t1;
}
};
时间复杂度:O(min(m,n)),对两个二叉树同时进行深度优先搜索,当其中一个节点为null而另一个节点不为null的时候,就直接返回非null的那个子树了,不用继续向下遍历了,所以只需要遍历小的子树
空间复杂度:O(min(m,n))。空间复杂度取决于递归调用的层数,递归调用的层数不会超过较小的二叉树的最大高度,最坏情况下,二叉树的高度等于节点数。