判断树T2是否为T1的子树

题目


你有两颗非常大的二叉树:T1,有几百万个节点;T2有几百个节点。
设计一个算法,判断T2是否为T1的子树。
如果T1有一个节点n,其子树与T2一模一样,则T2为T1的子树。也就是说,从节点n
处把树砍断,得到的树与T2完全相同。

分析


方法一:在规模较小且较简单的问题中,我们可以创建一个字符串,表示中序和前序遍历结果。若T2的前序遍历是T1前序遍历的子串,并且T2中序遍历是T1中序遍历的子串,则T2是T1的子树。
利用后缀树可以在线性时间内检查是否为子串,因此就最差情况的时间复杂度而言,这个算法是相当高效的。但是就本题而言,数据量过大,空间开销过大。

方法二:搜索较大的树T1,每当T1的某个节点与T2的根节点相同时,就调用matchTree方法判断T1子树与T2是否完全匹配;

代码

/*
题目:你有两颗非常大的二叉树:T1,有几百万个节点;T2有几百个节点。
设计一个算法,判断T2是否为T1的子树。

如果T1有一个节点n,其子树与T2一模一样,则T2为T1的子树。也就是说,从节点n
处把树砍断,得到的树与T2完全相同。
*/
#include <iostream>
#include <cstdlib>
#include <vector>
#include <queue>

using namespace std;

/*二叉树节点数据结构*/
struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
		val(x), left(NULL), right(NULL) {
	}
};

const int flag = INT_MAX;
TreeNode *generateTree(vector<int> &nums)
{
	if (nums.empty())
		return NULL;

	TreeNode *root = new TreeNode(nums[0]);
	queue<TreeNode *> que;
	que.push(root);
	//求出所给元素个数,对应二叉查找树节点个数
	int size = nums.size();
	for (int i = 1; i < size; i += 2)
	{
		//处理队首节点的左右子树
		TreeNode *tmp = que.front();
		TreeNode *left = NULL, *right = NULL;
		//定义非空左子树
		if (nums[i] != flag)
		{
			left = new TreeNode(nums[i]);
			que.push(left);
		}

		//定义非空右子树
		if (i + 1 < size && nums[i + 1] != flag)
		{
			right = new TreeNode(nums[i + 1]);
			que.push(right);
		}

		tmp->left = left;
		tmp->right = right;
		//弹出当前处理的节点
		que.pop();
	}
	return root;
}

class Solution {
public:
	bool containsTree(TreeNode *t1, TreeNode *t2)
	{
		if (t2 == NULL)
			return true;

		return subTree(t1, t2);
	}

	/*判断t2是否为t1的子树*/
	bool subTree(TreeNode *t1, TreeNode *t2)
	{
		if (t1 == NULL)
			return false;
		
		if (t1->val == t2->val)
			return matchTree(t1, t2);
		else
			return subTree(t1->left, t2) || subTree(t1->right, t2);
	}

	/*判断两颗树是否完全一致*/
	bool matchTree(TreeNode *t1, TreeNode *t2)
	{
		if (t1 == NULL && t2 == NULL)
			return true;
		else if (t1 == NULL || t2 == NULL)
			return false;
		else if (t1->val != t2->val)
			return false;
		else
			return matchTree(t1->left, t2->left) && matchTree(t1->right, t2->right);
	}

};

int main()
{
	vector<int> v1 = { 7, 6, flag, 4, flag, 2, 5, 8, 3, flag, flag, flag, flag, flag, flag };
	TreeNode *t1 = generateTree(v1);

	vector<int> v2 = {2, 8, 3};
	TreeNode *t2 = generateTree(v2);

	cout << Solution().containsTree(t1, t2) << endl;
	system("pause");
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值