题目介绍
描述:
给定两个非空二叉树 s 和 t,检验 s 中是否包含和 t 具有相同结构和节点值的子树。s 的一个子树包括 s 的一个节点和这个节点的所有子孙。s 也可以看做它自身的一棵子树。
示例 1:
给定的树 s:
3
/ \\
4 5
/ \\
1 2
给定的树 t:
4
/ \\
1 2
返回 true,因为 t 与 s 的一个子树拥有相同的结构和节点值。
示例 2:
给定的树 s:
3
/ \\
4 5
/ \\
1 2
/
0
给定的树 t:
4
/ \\
1 2
返回 false。
解题思路:
递归算法的关键是要明确函数的「定义」是什么,然后相信这个定义,利用这个定义推导最终结果。
写树相关的算法,简单说就是,先搞清楚当前 root 节点该做什么,然后根据函数定义递归调用子节点,递归调用会让孩子节点做相同的事情。
二叉树题目的一个难点在于如何通过题目的要求思考出每一个节点需要做什么
二叉树解题策略
一 递归 二 队列 + 迭代 (层次遍历) 三 栈 + 迭代 (非递归遍历) 四 其它
三种基本的遍历方式,都可以用递归来实现。写递归算法的时候,需要注意递归退出条件以及递归操作的表达。
自己的解法实现
def isSubtree4(self, s, t):
def isSub(s, t):
if not s and not t: return True
if s and t and s.val == t.val:
return isSub(s.left, t.left) and isSub(s.right, t.right)
def dfs(s, t):
if not s: return False
if s.val == t.val:
if isSub(s, t): return True
return dfs(s.left, t) or dfs(s.right, t)
return dfs(s, t)
网上比较优秀的解法
解法一
要判断一个树 t 是不是树 s 的子树,那么可以判断 t 是否和树 s 的任意子树相等。 即,这个题的做法就是在 s 的每个子节点上,判断该子节点是否和 t 相等。
判断两个树是否相等的三个条件是与的关系,即:
当前两个树的根节点值相等; 并且,s 的左子树和 t 的左子树相等; 并且,s 的右子树和 t 的右子树相等。 而判断 t 是否为 s 的子树的三个条件是或的关系,即:
- 当前两棵树相等;
- 或者,t 是 s 的左子树;
- 或者,t 是 s 的右子树。
def isSubtree(self, s, t):
if not s and not t:
return True
if not s or not t:
return False
return self.isSameTree(s, t) or self.isSubtree(s.left, t) or self.isSubtree(s.right, t)
def isSameTree(self, s, t):
if not s and not t:
return True
if not s or not t:
return False
return s.val == t.val and self.isSameTree(s.left, t.left) and self.isSameTree(s.right, t.right)
解法二
方法一:DFS 暴力匹配 思路和算法
这是一种最朴素的方法 —— DFS 枚举 ss 中的每一个节点,判断这个点的子树是否和 tt 相等。如何判断一个节点的子树是否和 tt 相等呢,我们又需要做一次 DFS 来检查,即让两个指针一开始先指向该节点和 tt 的根,然后「同步移动」两根指针来「同步遍历」这两棵树,判断对应位置是否相等。
def isSubtree2(self, s, t):
def dfs(s, t):
if not s: return False
return check(s, t) or dfs(s.left, t) or dfs(s.right, t)
def check(node1, node2):
if not node1 and not node2: return True
if not node1 or not node2: return False
if node1.val == node2.val:
return check(node1.left, node2.left) and check(node1.right, node2.right)
return dfs(s, t)
解法三
解法的原理是,class TreeNode 实现了 str() 方法,这个方法里存在递归调用,于是可以输出整个树的字符串表示,然后只需要进行子串查找即可。
def isSubtree3(self, s, t):
return str(t) in str(s)
解法四
这种题目的类型就是搜索,我们需要对树中的每一个节点都进行一次搜索,并以其为根节点进行递归比较。
def isSubtree5(self, s, t):
def helper(node1, node2):
if not node2: return not node1
if not node1: return not node2
if node1.val != node2.val: return False
return helper(node1.left, node2.left) and helper(node1.right, node2.right)
if not s: return False
return helper(s, t) or self.isSubtree(s.left, t) or self.isSubtree(s.right, t)
相关知识总结和思考
相关知识:
BFS:广度/宽度优先。其实就是从上到下,先把每一层遍历完之后再遍历一下一层。
可以使用Queue的数据结构。我们将root节点初始化进队列,通过消耗尾部,插入头部的方式来完成BFS。
二叉搜索树(BST)的特性:
- 若它的左子树不为空,则所有左子树上的值均小于其根节点的值
- 若它的右子树不为空,则所有右子树上的值均大于其根节点的值
- 它的左右子树也分别为二叉搜索树
递归与迭代的区别
递归:重复调用函数自身实现循环称为递归; 迭代:利用变量的原值推出新值称为迭代,或者说迭代是函数内某段代码实现循环;