LeetCode617. 合并二叉树

617. 合并二叉树


一、题目

给你两棵二叉树: root1root2

想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。

返回合并后的二叉树。

注意: 合并过程必须从两个树的根节点开始。

示例 1:

img

输入:root1 = [1,3,2,5], root2 = [2,1,3,null,4,null,7]
输出:[3,4,5,5,4,null,7]

示例 2:

输入:root1 = [1], root2 = [1,2]
输出:[2,2]

提示:

  • 两棵树中的节点数目在范围 [0, 2000]
  • -104 <= Node.val <= 104
二、题解
方法一:递归

首先需要明确我们的目标:合并两棵二叉树,使得合并后的树上的节点按照规则进行组合。我们可以分析题目中的合并规则,即如果两个节点重叠,将它们的值相加作为新节点的值;如果其中一个节点为空,另一个节点不为空,则将不为空的节点直接作为新树的节点。

算法思路

  1. 首先,我们需要考虑递归的终止条件。当两棵树的当前节点都为空时,合并结果为nullptr,递归终止。
  2. 若其中一棵树的节点为空,我们应该返回另一棵树的节点作为合并结果,因为另一棵树的节点不为空。
  3. 如果两棵树的节点都不为空,我们将它们的值相加创建一个新的节点,然后递归合并左子树和右子树。

具体实现

我们可以使用递归来实现这个合并过程。

/**
 * 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) {
        // Base case: if both nodes are nullptr, return nullptr
        if (root1 == nullptr && root2 == nullptr) {
            return nullptr;
        }
        
        // If one node is nullptr, return the other node
        if (root1 == nullptr) {
            return root2;
        }
        
        if (root2 == nullptr) {
            return root1;
        }
        
        // Create a new node with the sum of values from both nodes
        TreeNode* mergedNode = new TreeNode(root1->val + root2->val);
        
        // Recursively merge left and right subtrees
        mergedNode->left = mergeTrees(root1->left, root2->left);
        mergedNode->right = mergeTrees(root1->right, root2->right);
        
        return mergedNode;
    }
};

算法分析:

  1. 时间复杂度:我们遍历了两棵树的所有节点一次,所以时间复杂度是 O(N),其中 N 是两棵树中节点的总数。
  2. 空间复杂度:递归的栈空间是主要的空间消耗,最坏情况下,递归栈的深度等于树的高度,所以空间复杂度是 O(H),其中 H 是树的高度。
方法二:迭代

算法思路

  1. 首先,我们需要处理特殊情况。如果两棵树的根节点都为空,那么合并后的树也为空,直接返回 nullptr。如果其中一棵树的根节点为空,我们返回另一棵树的根节点,表示直接采用非空树的结构作为合并后的树。
  2. 如果两棵树的根节点都不为空,我们可以进行合并。
  3. 然后,我们使用迭代(非递归)的方式来进行树的合并。我们可以维护三个队列:deq1 用于存储第一棵树的节点,deq2 用于存储第二棵树的节点,MergeDeq 用于存储合并后树的节点。
  4. 我们将根节点 root 分别放入 deq1deq2MergeDeq 中,表示当前正在合并这三个节点。
  5. 接下来,我们开始迭代处理队列中的节点,直到队列为空。在每一轮迭代中,我们从 deq1deq2 中分别取出一个节点 node1node2,从 MergeDeq 中取出一个节点 nodem
  6. 首先,我们判断 node1node2 是否有左子节点。如果两个节点都有左子节点,我们新建一个左子节点 leftNode,将其值设置为 node1->left->val + node2->left->val,然后将 leftNode 设置为 nodem 的左子节点,将 node1->leftnode2->left 分别放入 deq1deq2 中,将 leftNode 放入 MergeDeq 中。
  7. 如果只有 node1 有左子节点,我们将 node1->left 设置为 nodem 的左子节点;如果只有 node2 有左子节点,我们将 node2->left 设置为 nodem 的左子节点。
  8. 类似地,我们对右子节点进行相同的操作。
  9. 最终,迭代完成后,我们得到了合并后的树。

具体实现

下面是具体的代码实现,包括了上述思路中的各个步骤:

class Solution {
public:
    TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
        if (root1 == nullptr && root2 == nullptr) {
            return nullptr;
        } else if (root1 == nullptr) {
            return root2;
        } else if (root2 == nullptr) {
            return root1;
        }

        TreeNode* root = new TreeNode();
        root->val = root1->val + root2->val;

        deque<TreeNode*> deq1;
        deque<TreeNode*> deq2;
        deque<TreeNode*> MergeDeq;
        deq1.push_back(root1);
        deq2.push_back(root2);
        MergeDeq.push_back(root);

        while (!deq1.empty() && !deq2.empty()) {
            TreeNode* node1 = deq1.front();
            TreeNode* node2 = deq2.front();
            TreeNode* nodem = MergeDeq.front();
            deq1.pop_front();
            deq2.pop_front();
            MergeDeq.pop_front();

            if (node1->left && node2->left) {
                TreeNode* leftNode = new TreeNode();
                leftNode->val = node1->left->val + node2->left->val;
                nodem->left = leftNode;
                deq1.push_back(node1->left);
                deq2.push_back(node2->left);
                MergeDeq.push_back(leftNode);
            } else if (node1->left) {
                nodem->left = node1->left;
            } else if (node2->left) {
                nodem->left = node2->left;
            }

            if (node1->right && node2->right) {
                TreeNode* rightNode = new TreeNode();
                rightNode->val = node1->right->val + node2->right->val;
                nodem->right = rightNode;
                deq1.push_back(node1->right);
                deq2.push_back(node2->right);
                MergeDeq.push_back(rightNode);
            } else if (node1->right) {
                nodem->right = node1->right;
            } else if (node2->right) {
                nodem->right = node2->right;
            }
        }
        return root;
    }
};

算法分析

  • 时间复杂度:假设第一棵树有 n 个节点,第二棵树有 m 个节点。在最坏情况下,我们需要遍历所有节点一次,因此时间复杂度为 O(n + m)
  • 空间复杂度:我们使用了三个队列来存储节点,每个队列的大小不会超过树的节点数,因此空间复杂度为 O(n + m)

当然两个队列也可以做这道题(将root2合并给root1):

class Solution {
public:
    TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
        if (root1 == NULL) return root2;
        if (root2 == NULL) return root1;
        queue<TreeNode*> que;
        que.push(root1);
        que.push(root2);
        while(!que.empty()) {
            TreeNode* node1 = que.front(); que.pop();
            TreeNode* node2 = que.front(); que.pop();
            // 此时两个节点一定不为空,val相加
            node1->val += node2->val;

            // 如果两棵树左节点都不为空,加入队列
            if (node1->left != NULL && node2->left != NULL) {
                que.push(node1->left);
                que.push(node2->left);
            }
            // 如果两棵树右节点都不为空,加入队列
            if (node1->right != NULL && node2->right != NULL) {
                que.push(node1->right);
                que.push(node2->right);
            }

            // 当root1的左节点为空,root2左节点不为空,就赋值过去(root2给root1)
            if (node1->left == NULL && node2->left != NULL) {
                node1->left = node2->left;
            }
            // 当root1的右节点为空,root2右节点不为空,同样的操作
            if (node1->right == NULL && node2->right != NULL) {
                node1->right = node2->right;
            }
        }
        return root1;
    }
};
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

KeepCoding♪Toby♪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值