[剑指Offer] 26_树的子结构
题目
输入两棵二叉树A和B,判断B是不是A的子结构。
例:
A B
8 8
8 7 9 2
9 2
4 7
A树中有一部分子树和B是一样的,因此B是A的子结构。
思路
- 在A树中搜索和B树的root的val一样的节点,并从该节点向下逐个比对,如果B树遍历比对完成则表示是子结构,否则返回重新寻找root,直到A树遍历完毕。
- 时间复杂度:O(nlogn),如果A树中除了最右节点其余全部节点都和B树的全部节点值相同,A、B一样高,将会T(n) = 2T(n/2) + O(n)
- 空间复杂度:O(logn)递归深度
- 将A、B树的前序遍历缓存成字符串,比对B是否是A的子串,相同则表示匹配。比较是否字串使用in关键词,应该是O(n)。的因为B的大小是固定的,只要截取固定长度的字符串比较他们的哈希值 O(1),比较n次即可。
- 时间复杂度:O(n)
- 空间复杂度:O(n)
代码
思路1:时间复杂度:O(nlogn),空间复杂度:O(logn)
def substrucure_in_tree(main, sub):
"""
:param main: Big Tree
:param sub: substructure
:return: bool
"""
def compare(main_tree_sub, sub):
"""
:param main_tree_sub: node
:param sub: substructure_root
:return: bool
"""
if not sub:
return True
if not main_tree_sub:
return False
if sub.val == main_tree_sub.val:
return compare(main_tree_sub.left, sub.left) and compare(main_tree_sub.right, sub.right)
return False
if not main:
return False
if main.val == sub.val and compare(main, sub):
return True
else:
return substrucure_in_tree(main.left, sub) or substrucure_in_tree(main.right, sub)
return
思路2:时间复杂度:O(n) ,空间复杂度:O(n)
def substrucure_in_tree_2(main, sub):
def preorder(root):
return (root.val, preorder(root.left), preorder(root.right)) if root else None
return str(preorder(sub)) in str(preorder(main))
思考
思路2是在LeetCode上看到的解法,相当于用空间换时间了。很有意思,代码很简洁。从另一个角度看,思路1对于极端情况重复比较和计算了很多次,所以思路2相当于添加了缓存,也就是备忘录法解决公共子问题,也是dp思想中的一点运用吧。
相似的题目,但是此题要求子孙节点严格相等,而不是覆盖。
LeetCode 572. 另一个树的子树
题目
给定两个非空二叉树 s 和 t,检验 s 中是否包含和 t 具有相同结构和节点值的子树。s 的一个子树包括 s 的一个节点和这个节点的所有子孙。s 也可以看做它自身的一棵子树。