求解二叉树中两个节点的最近公共祖先(LCA)

本文介绍了解决二叉树中寻找两个节点的最低公共祖先(LCA)问题的两种方法:一种是非递归方法,通过记录从根节点到目标节点的路径来找出LCA;另一种是递归方法,利用二叉树的结构特性来高效查找LCA。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/************************************************************************/
/* 
非递归的方法

下面是一个简单的复杂度为 O(n) 的算法,解决LCA问题

1) 找到从根到n1的路径,并存储在一个向量或数组中。
2)找到从根到n2的路径,并存储在一个向量或数组中。
3) 遍历这两条路径,直到遇到一个不同的节点,则前面的那个即为最低公共祖先.

*/
/************************************************************************/


//二叉树节点
struct Node
{
	int key;
	Node *left, *right;
};

//找到从root到 节点值为key的路径,存储在path中。没有的话返回-1
bool findpath(Node * root,vector<int> &path,int key)
{
	if(root == NULL) return false;
	path.push_back(root->key);
	if(root->key == key) return true;
	//左子树或右子树 是否找到,找到的话当前节点就在路径中了
	bool find =  ( findpath(root->left, path, key) || findpath(root->right,path ,key) );
	if(find) return true;
	//该节点下未找到就弹出
	path.pop_back();
	return false;
}

int findLCA(Node * root,int key1,int key2)
{
	vector<int> path1,path2;
	bool find1 = findpath(root, path1, key1);
	bool find2 = findpath(root, path2, key2);
	if(find1 && find2)
	{
		int ans ;
		for(int i=0; i < path1.size(); i++)
		{
			if(path1[i] != path2[i])
			{
				break;
			}
			else
			{
				ans = path1[i];
			}
		}
		return ans;
	}
	return -1;
}



/************************************************************************/
/* 
递归求解方法

从root开始遍历,如果n1和n2中的任一个和root匹配,那么root就是LCA。
如果都不匹配,则分别递归左、右子树,
如果有一个 key(n1或n2)出现在左子树,并且另一个key(n1或n2)出现在右子树,则root就是LCA.  
如果两个key都出现在左子树,则说明LCA在左子树中,否则在右子树。
*/
/************************************************************************/


struct Node
{
	struct Node *left, *right;
	int key;
};

// 返回n1和n2的 LCA的指针
// 假设n1和n2都出现在树中
struct Node *findLCA(struct Node* root, int n1, int n2)
{
	if (root == NULL) return NULL;

	// 只要n1 或 n2 的任一个匹配即可
	//  (注意:如果 一个节点是另一个祖先,则返回的是祖先节点。因为递归是要返回到祖先的 )
	if (root->key == n1 || root->key == n2)
		return root;
	// 分别在左右子树查找
	Node *left_lca  = findLCA(root->left, n1, n2);
	Node *right_lca = findLCA(root->right, n1, n2);
	// 如果都返回非空指针 Non-NULL, 则说明两个节点分别出现了在两个子树中,则当前节点肯定为LCA
	if (left_lca && right_lca)  return root;
	// 如果一个为空,在说明LCA在另一个子树
	return (left_lca != NULL)? left_lca: right_lca;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值