题解 | #树的子结构#
树的子结构
http://www.nowcoder.com/practice/6e196c44c7004d15b1610b9afca8bd88
描述
这是一篇面对初级coder的题解。
知识点:链表 递归 DFS
难度:三星
题解
题目:输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)
考察树的基础知识与递归的思路,深度优先搜索。
方法一:递归求解
思路:双重递归
递归一:递归判断子树中有无子结构
对应HasSubtree()
递归二:判断当前树根是否对应子结构
对应issame()函数
class Solution { public: bool IsSame(TreeNode* pRoot1, TreeNode* pRoot2)//递归判断是否是子结构 { bool left=true,right=true;//左右是否相同 空的时候默认均匹配 if(!pRoot1||pRoot1->val!=pRoot2->val) //判断头节点 return false; if(pRoot2->left)//递归判断左侧节点,需要判断子结构是否为空 left=IsSame(pRoot1->left, pRoot2->left); if(pRoot2->right)//递归判断右侧节点,需要判断子结构是否为空 right=IsSame(pRoot1->right, pRoot2->right); return left&&right;//左右节点都相同才是子结构 } bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2) //递归判断子树里有无所求子结构 { if(!pRoot2||!pRoot1) //边界条件 空树返回false return false; if(IsSame(pRoot1, pRoot2))//递归判断是否是子结构 return true; if(HasSubtree(pRoot1->left,pRoot2)||HasSubtree(pRoot1->right,pRoot2))//递归判断左右节点有无子结构 return true; else return false; } };
复杂度分析:
时间复杂度 O(MN): 其中 M,N 分别为树 A 和 树 B 的节点数量;先序遍历树 A 占用 O(M) ,每次调用IsSame(TreeNode* pRoot1, TreeNode* pRoot2)判断占用 O(N)。
空间复杂度 O(M) : 当树 A 和树 B 都退化为链表时,递归调用深度最大。当 M ≤N 时,遍历树 A 与递归判断的总递归深度为 M ;当 M>N时,最差情况为遍历至树 A叶子节点,此时总递归深度为 M。
运行时间11ms 占用内存600KB
总结
递归的解法在树的解题中有广泛应用:
如下动图展示了深度优先搜索的递归算法:
解题模板
下面给出二叉树对称性递归的解题模板
1、递归结束条件:特殊情况的判断
如果是单树问题,一般来说只要进行以下判断:
下面给出二叉树对称性递归的解题模板
1、递归结束条件:特殊情况的判断
如果是单树问题,一般来说只要进行以下判断:
if(!root) return true/false; if(!root->left) return true/false/递归函数; if(!root->right) return true/false/递归函数;如果是双树问题(根节点分别为p,q),一般来说进行以下判断:
if(!p && !q) return true/false; if(!p || !q) return true/false;
当然也不完全是这些情况,比如有的需要加上节点值的判断,需要具体问题需要具体分析
2、返回值
通常对称性递归的返回值是多个条件的复合判断语句
可能是以下几种条件判断的组合:
节点非空的判断
节点值比较判断
(单树)调用根节点左右子树的递归函数进行递归判断
(双树)调用两棵树的左右子树的递归函数进行判断
阿Q的题解 文章被收录于专栏
阿Q秋招刷过的题