题目描述:
检查子树。你有两棵非常大的二叉树:T1,有几万个节点;T2,有几万个节点。设计一个算法,判断 T2 是否为 T1 的子树。
如果 T1 有这么一个节点 n,其子树与 T2 一模一样,则 T2 为 T1 的子树,也就是说,从节点 n 处把树砍断,得到的树与 T2 完全相同。
示例:
思路与题解:
看到题目要求,这种包含关系,第一时间我想的是把二叉树与字符串进行转换,然后判断:
return !(s1.find(s2)==string::npos);
其中s1为t1树中序遍历的结果,s2为t2树中序遍历的结果,具体遍历过程如下:
void inorder(TreeNode* node,string s)
{
if(node==nullptr)return;
inorder(node->left,s);
s += to_string(node->val);
inorder(node->right,s);
}
但是,仔细一想,就发现其中的不对,居然力扣上还有人把它当作正确题解发了出来—错误代码,我觉得更是大错特错! 如果他能通过测试用例的话,只能说力扣的测试用例不严谨。举两个例子,对于下方的二叉树而言:
如下的两棵树,进行上述操作后能返回true,但实际结果应该为false:
所以,正确的解法应该为深度优先搜索(dfs),思路如下:
对 t1 及其左右子树分别用 dfs 算法,若其中一项满足要求则返回true,否则返回false。
具体实现代码如下:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
bool checkSubTree(TreeNode* t1, TreeNode* t2) {
if(t1==NULL)return t2==NULL;
if(t2==NULL)return true;
return dfs(t1,t2)||checkSubTree(t1->left,t2)||checkSubTree(t1->right,t2);
}
bool dfs(TreeNode* t1,TreeNode* t2)
{
if((t1==NULL&&t2!=NULL)||(t1!=NULL&&t2==NULL))return false;
if(t1==NULL&&t2==NULL)return true;
return (t1->val==t2->val)&&dfs(t1->left,t2->left)&&dfs(t1->right,t2->right);
}
};
由于dfs最长深度为n,搜寻t1值与t2值的时间也为O(n),但由于C++的短路原则,算法整体时间复杂度为O(n),空间复杂度为O(1),满足题目所述的万节点要求,最终运行评价如下: