1、给你两棵二叉树: root1 和 root2 。想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。返回合并后的二叉树。
注意: 合并过程必须从两个树的根节点开始
示例:输入:root1 = [1,3,2,5], root2 = [2,1,3,null,4,null,7] 输出:[3,4,5,5,4,null,7]
(1)深度优先搜索(DFS)
首先我们可以考虑深度优先搜索,从一个较大的二叉树开始深度遍历,然后两者加和。
代码:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
if (root1== nullptr){
return root2;
}
if(root2 == nullptr){
return root1;
}
auto merge = new TreeNode(root1 ->val+root2 -> val);
merge->left = mergeTrees(root1->left,root2->left);
merge->right = mergeTrees(root1->right,root2->right);
return merge;
}
};
时间复杂度大概是Omin(m,n);空间复杂度Omin(m,n)
(2)广度优先搜索(BFS)
代码:
class Solution {
public:
TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
if (t1 == nullptr) {
return t2;
}
if (t2 == nullptr) {
return t1;
}
auto merged = new TreeNode(t1->val + t2->val);
auto q = queue<TreeNode*>();
auto queue1 = queue<TreeNode*>();
auto queue2 = queue<TreeNode*>();
q.push(merged);
queue1.push(t1);
queue2.push(t2);
while (!queue1.empty() && !queue2.empty()) {
auto node = q.front(), node1 = queue1.front(), node2 = queue2.front();
q.pop();
queue1.pop();
queue2.pop();
auto left1 = node1->left, left2 = node2->left, right1 = node1->right, right2 = node2->right;
if (left1 != nullptr || left2 != nullptr) {
if (left1 != nullptr && left2 != nullptr) {
auto left = new TreeNode(left1->val + left2->val);
node->left = left;
q.push(left);
queue1.push(left1);
queue2.push(left2);
} else if (left1 != nullptr) {
node->left = left1;
} else if (left2 != nullptr) {
node->left = left2;
}
}
if (right1 != nullptr || right2 != nullptr) {
if (right1 != nullptr && right2 != nullptr) {
auto right = new TreeNode(right1->val + right2->val);
node->right = right;
q.push(right);
queue1.push(right1);
queue2.push(right2);
} else if (right1 != nullptr) {
node->right = right1;
} else {
node->right = right2;
}
}
}
return merged;
}
};
2、给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:
struct Node {
int val;
Node *left;
Node *right;
Node *next;
}
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。初始状态下,所有 next 指针都被设置为 NULL。示例:
输入:root = [1,2,3,4,5,6,7] 输出:[1,#,2,3,#,4,5,6,7,#]
对于这种情况,我们能想到的就是层次遍历。
(1)层次遍历
代码:
class Solution {
public:
Node* connect(Node* root) {
if (root == nullptr) {
return root;
}
// 初始化队列同时将第一层节点加入队列中,即根节点
queue<Node*> Q;
Q.push(root);
// 外层的 while 循环迭代的是层数
while (!Q.empty()) {
// 记录当前队列大小
int size = Q.size();
// 遍历这一层的所有节点
for(int i = 0; i < size; i++) {
// 从队首取出元素
Node* node = Q.front();
Q.pop();
// 连接
if (i < size - 1) {
node->next = Q.front();
}
// 拓展下一层节点
if (node->left != nullptr) {
Q.push(node->left);
}
if (node->right != nullptr) {
Q.push(node->right);
}
}
}
// 返回根节点
return root;
}
};
(因为自己的代码不知道为什么就是超出时间限制,因此使用这一个)
遍历的话时间复杂度为O(n),空间复杂度因为有队列,所以是O(n)。
(2)利用已有next指针
class Solution {
public:
Node* connect(Node* root) {
if(root == nullptr){
return root;
}
Node*leftmost = root;
while(leftmost->left != nullptr){ //最后一个节点的left等于null
Node*head =leftmost;
while(head != nullptr){
head->left->next = head->right; //左右孩子连接
if(head->next != nullptr){
head->right->next = head->next->left; //不同根节点彼此连接
}
head = head->next; //next指针移动
}
leftmost = leftmost->left; //进入下一层,如果是最后一个则没有left,得到nullptr结束循环
}
return root;
}
};
真是令人眼花缭乱的指针啊。。。。。这里的时间复杂度O(n),空间复杂度O(1)(没有建立队列)。