题解:相同的树(100. 相同的树)

问题描述

        给定两棵二叉树的根节点 p 和 q,编写一个函数来检验这两棵树是否相同。若两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

方法一:深度优先搜索(DFS)

思路与算法

        深度优先搜索(DFS)是一种常见的遍历树的方法,通过递归实现。DFS 的基本思路如下:

1. 基础情况:
   - 如果两个节点都为空,则认为它们是相同的。
   - 如果其中一个节点为空,另一个不为空,则认为它们不同。
   - 如果两个节点的值不同,则认为它们不同。

2. 递归检查:
   - 递归检查左子树:isSameTree(p.left, q.left)。
   - 递归检查右子树:isSameTree(p.right, q.right)。

代码实现

class Solution {
public:
    bool isSameTree(TreeNode* p, TreeNode* q) {
        if (p == nullptr && q == nullptr) {
            return true;
        } else if (p == nullptr || q == nullptr) {
            return false;
        } else if (p->val != q->val) {
            return false;
        } else {
            return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
        }
    }
};

复杂度分析

- 时间复杂度:O(min(m, n)),其中 m 和 n 分别是两棵二叉树的节点数。我们对两棵树进行递归遍历,当节点不相同时立即返回 false,访问的节点数不会超过较小的二叉树的节点数。

- 空间复杂度:O(min(m, n)),取决于递归调用的栈深度,最坏情况下,栈深度等于较小树的高度。

方法二:广度优先搜索(BFS)

思路与算法

        广度优先搜索(BFS)是一种逐层遍历树的算法。我们可以使用两个队列来实现 BFS:

1. 初始化:
   - 如果两棵树都为空,则它们相同,返回 true。
   - 如果其中一个为空,另一个不为空,则它们不同,返回 false。

2. 队列操作:
   - 使用两个队列分别存储两个二叉树的节点,初始时将根节点加入队列。
   - 每次从两个队列中各取出一个节点进行比较。
   - 如果节点的值不同,则返回 false。
   - 如果左孩子或者右孩子的结构不同(一个为空,另一个不为空),则返回 false。这里使用异或操作 ^ 判断其中一个节点为空而另一个不为空的情况,简化了代码逻辑。
   - 将非空的子节点分别加入队列。

3. 结束条件:
   - 当两个队列同时为空时,说明两棵树相同,返回 true。

代码实现

class Solution {
public:
    bool isSameTree(TreeNode* p, TreeNode* q) {
        if (p == nullptr && q == nullptr) {
            return true;
        } else if (p == nullptr || q == nullptr) {
            return false;
        }

        queue<TreeNode*> queue1, queue2;
        queue1.push(p);
        queue2.push(q);

        while (!queue1.empty() && !queue2.empty()) {
            TreeNode* node1 = queue1.front(); queue1.pop();
            TreeNode* node2 = queue2.front(); queue2.pop();

            if (node1->val != node2->val) {
                return false;
            }

            TreeNode* left1 = node1->left, *right1 = node1->right;
            TreeNode* left2 = node2->left, *right2 = node2->right;

            if ((left1 == nullptr) ^ (left2 == nullptr)) {
                return false;
            }
            if ((right1 == nullptr) ^ (right2 == nullptr)) {
                return false;
            }

            if (left1 != nullptr) queue1.push(left1);
            if (right1 != nullptr) queue1.push(right1);
            if (left2 != nullptr) queue2.push(left2);
            if (right2 != nullptr) queue2.push(right2);
        }

        return queue1.empty() && queue2.empty();
    }
};

复杂度分析

- 时间复杂度:O(min(m, n)),我们对两个树进行同步 BFS,当节点不相同时立即返回 false,遍历的节点数不会超过较小树的节点数。


- 空间复杂度:O(min(m, n)),取决于队列中存储的节点数量,最坏情况下队列的大小等于较小树的节点数。

优化与不足

1. DFS 方法:如果树的高度较大,递归调用可能会导致栈溢出。在这种情况下,BFS 是一个更安全的选择。但是DFS代码少,简单。
2. BFS 方法:BFS 在遍历树时使用显式队列,避免了深度递归的栈深度问题,并且可以通过异或操作 ^ 简化判断左右子树结构是否相同的代码逻辑。但是BFS代码多,难度较大。

3. 代码:代码大量使用 if 和else if,过于臃肿,不够优美。但是学习理解更加容易。

总结

        在这类题目中,常用的遍历树的方法包括深度优先搜索(DFS)和广度优先搜索(BFS)。DFS 通常实现简单,但在处理深度大的树时需要注意栈溢出问题。BFS 则使用队列来实现,不存在栈溢出风险,代码可读性也较好。通过这两种方法,我们可以有效地判断两棵树是否相同。这类问题的核心是对树的遍历和对节点的比较,掌握这些技巧可以帮助我们解决许多类似的树问题。

  • 14
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值