数据结构与算法之二叉树: LeetCode 100. 相同的树 (Ts, Py, Go版)

本文介绍了如何使用深度优先和广度优先递归/迭代方法判断两棵二叉树是否相同,条件是节点值相同且结构一致。两种方法的时间复杂度均为O(n),空间复杂度也为O(n)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

相同的树

  • https://leetcode.cn/problems/same-tree/

描述

  • 给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。

  • 如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

示例 1

  1         1
 /  \      /  \  
2    3    2    3   
输入:p = [1,2,3], q = [1,2,3]
输出:true

示例 2

  1      1
 /        \  
2          2
输入:p = [1,2], q = [1,null,2]
输出:false

示例 3

  1         1
 /  \      /  \  
2    1    1    2
输入:p = [1,2,1], q = [1,1,2]
输出:false

提示

  • 两棵树上的节点数目都在范围 [0, 100] 内
  • - 1 0 4 10^4 104 <= Node.val <= 1 0 4 10^4 104

Typescript 版算法实现


1 )深度优先递归版本

/**
 * Definition for a binary tree node.
 * class TreeNode {
 *     val: number
 *     left: TreeNode | null
 *     right: TreeNode | null
 *     constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
 *         this.val = (val===undefined ? 0 : val)
 *         this.left = (left===undefined ? null : left)
 *         this.right = (right===undefined ? null : right)
 *     }
 * }
 */

function isSameTree(p: TreeNode | null, q: TreeNode | null): boolean {
    // 都为空时
    if(!p && !q) return true;
    // 不相同时
    if (p?.val !== q?.val) return false;
    // 递归判断
    return isSameTree(p?.left, q?.left) && isSameTree(p?.right, q?.right);
};
  • 解题思路
    • 两棵树相同:根节点值相同,左子树相同,右子树相同
    • 如此一来,我们把若干大问题,分解成若干个相似小问题
    • 符合:分、解、合特性
    • 选择分而治之
  • 解题步骤
    • 分:获取两个树的左子树和右子树
    • 解:递归地判断两个树的左子树是否相同,右子树是否相同
    • 合:将上述结果合并,若根节点值也相同,树就相同
  • 时间复杂度:O(n)
    • n是所有节点数
  • 空间复杂度:O(n)
    • 递归,底部形成堆栈
    • n是树的节点数,最坏情况下,树的节点数是树的高度

2 )广度优先迭代版本

/**
 * Definition for a binary tree node.
 * class TreeNode {
 *     val: number
 *     left: TreeNode | null
 *     right: TreeNode | null
 *     constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
 *         this.val = (val===undefined ? 0 : val)
 *         this.left = (left===undefined ? null : left)
 *         this.right = (right===undefined ? null : right)
 *     }
 * }
 */

function isSameTree(p: TreeNode | null, q: TreeNode | null): boolean {
    // 都为空时
    if(!p && !q) return true;
    // 不相同时
    if (p?.val !== q?.val) return false;
    // 声明两个队列
    const queue1 = [p];
    const queue2 = [q];
    // 迭代对比
    while (queue1.length && queue2.length) {
        // 拿到队首
        const pTop = queue1.shift();
        const qTop = queue2.shift();
        // 对比判断, 符合则提前终止
        if (pTop.val !== qTop.val) return false;
        // 拿到下一层
        const pLeft = pTop?.left;
        const pRight = pTop?.right;
        const qLeft = qTop?.left;
        const qRight = qTop?.right;
        // 进入判断, 符合则提前终止
        if ((pLeft && !qLeft) || (!pLeft && qLeft)) return false;
        if ((pRight && !qRight) || (!pRight && qRight)) return false;
        // 进入队列
        if (pLeft) queue1.push(pLeft);
        if (pRight) queue1.push(pRight);
        if (qLeft) queue2.push(qLeft);
        if (qRight) queue2.push(qRight);
    }
    // 最终结果对比
    return !queue1.length && !queue2.length;
}
  • 这里换一种广度优先遍历来对比两棵树是否相同
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

Python3 版算法实现


1 ) 方案1

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def isSameTree(self, p: Optional[TreeNode], q: Optional[TreeNode]) -> bool:
        # 都为空时
        if not p and not q:
            return True
        # 不相同时
        if not p or not q or p.val != q.val:
            return False
        # 递归判断
        return self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right)

2 ) 方案2

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right

class Solution:
    def isSameTree(self, p: Optional[TreeNode], q: Optional[TreeNode]) -> bool:
        # 都为空时
        if not p and not q:
            return True
        # 不相同时
        if not p or not q or p.val != q.val:
            return False
        # 声明两个队列
        queue1 = [p]
        queue2 = [q]
        # 迭代对比
        while queue1 and queue2:
            # 拿到队首
            pTop = queue1.pop(0)
            qTop = queue2.pop(0)
            # 对比判断, 符合则提前终止
            if pTop.val != qTop.val:
                return False
            # 拿到下一层
            pLeft = pTop.left
            pRight = pTop.right
            qLeft = qTop.left
            qRight = qTop.right
            # 进入判断, 符合则提前终止
            if (pLeft and not qLeft) or (not pLeft and qLeft):
                return False
            if (pRight and not qRight) or (not pRight and qRight):
                return False
            # 进入队列
            if pLeft:
                queue1.append(pLeft)
            if pRight:
                queue1.append(pRight)
            if qLeft:
                queue2.append(qLeft)
            if qRight:
                queue2.append(qRight)
        # 最终结果对比
        return not queue1 and not queue2

Golang 版算法实现


1 ) 方案1

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */

func isSameTree(p *TreeNode, q *TreeNode) bool {
	// 都为空时
	if p == nil && q == nil {
		return true
	}
	// 不相同时
	if p == nil || q == nil || p.Val != q.Val {
		return false
	}
	// 递归判断
	return isSameTree(p.Left, q.Left) && isSameTree(p.Right, q.Right)
}

2 ) 方案2

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */

func isSameTree(p *TreeNode, q *TreeNode) bool {
	// 都为空时
	if p == nil && q == nil {
		return true
	}
	// 不相同时
	if p == nil || q == nil || p.Val != q.Val {
		return false
	}
	// 声明两个队列
	queue1 := []*TreeNode{p}
	queue2 := []*TreeNode{q}

	// 迭代对比
	for len(queue1) > 0 && len(queue2) > 0 {
		// 拿到队首
		pTop := queue1[0]
		qTop := queue2[0]
		queue1 = queue1[1:]
		queue2 = queue2[1:]

		// 对比判断, 符合则提前终止
		if pTop.Val != qTop.Val {
			return false
		}
		// 拿到下一层
		pLeft := pTop.Left
		pRight := pTop.Right
		qLeft := qTop.Left
		qRight := qTop.Right

		// 进入判断, 符合则提前终止
		if (pLeft != nil && qLeft == nil) || (pLeft == nil && qLeft != nil) {
			return false
		}
		if (pRight != nil && qRight == nil) || (pRight == nil && qRight != nil) {
			return false
		}
		// 进入队列
		if pLeft != nil {
			queue1 = append(queue1, pLeft)
		}
		if pRight != nil {
			queue1 = append(queue1, pRight)
		}
		if qLeft != nil {
			queue2 = append(queue2, qLeft)
		}
		if qRight != nil {
			queue2 = append(queue2, qRight)
		}
	}
	// 最终结果对比
	return len(queue1) == 0 && len(queue2) == 0
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Wang's Blog

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

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

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

打赏作者

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

抵扣说明:

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

余额充值