力扣-236-二叉树的最近公共祖先

一般来说二叉树是向下遍历的,这里要找公共祖先就要向上遍历

考虑到本身也可以是公共祖先的情况…没什么思路

但肯定跟遍历有关,而且或许涉及回溯
要么就需要额外的数据结构保存

好,题解的思路1是后序遍历

这里会不会出现树种有相同的节点?

可以把这个
if (root->val == p->val || root->val == q->val || (leftHas && rightHas)) return true;
写成这个
return (root->val == p->val || root->val == q->val || (leftHas && rightHas));

这是官方的题解思路代码

TreeNode* ans;

// 这个后序遍历方法多了两个参数,要查找的节点p、q
bool backTravel(TreeNode* root,TreeNode* p,TreeNode* q) {
	if (!root) return false;
	// 但是问题是怎么判断呢?怎么记录包不包含
// 用两个布尔值
	bool leftHas =  backTravel(root->left,p,q);
	bool rightHas = backTravel(root->right,p,q);
	// 返回的时机应该放在判断自己并向上返回状态之前
	// 因为如果子节点中都满足了
	// 返回的条件是1. 子树中已经有这两个目标了2. 子树中能满足一个,加上自己能满足一个就凑够了
	// 但是2的前提是不会出现重复元素吧,比如不能两边都有q
	if ((leftHas && rightHas) || (root->val == q->val || root->val == p->val) && (leftHas || rightHas))
		// 因为是递归,这里不能break
		// 那岂不是还会继续往上走?root会被刷新吗?
		ans = root;
	// 判断节点
	// 这里就通过这两个布尔值实现了向上的状态传递
	return (root->val == p->val || root->val == q->val || (leftHas && rightHas));
}

TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
	// 后续遍历,第一个想法肯定是递归,那迭代怎么写?
	backTravel(root, p, q);
	return ans;
}

但是有两个很明显的问题,1是它直接比较了节点的val而不是比较节点,这是不合适的,如果有两个val相同但是指针不同的不同节点,会被误判。

比如在某节点的左子树中有两个val相同都满足q的节点,可能就会被误判

另外一点就是,给ans赋值的时候,就算找到了是不是也会继续往上走?是的,但是不会刷新root了,因为如果一颗子树中找齐了,另一个子树是不可能再有的,同时根节点也不可能再有一致的了
但就算如此,不能break看起来仍然有多余的递归步骤

简化这题的不完美但是看起来很简洁的写法可以这么写

// 本质上使用节点指针替代了题解1中的bool变量
// 另外官解1中比较节点的val显然不合适
// 但是仍然存在多余的向上遍历,虽然这个过程中结果指针会向上传递,而且不会被覆盖保证了结果是正确的
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
	if (!root) return nullptr;

	TreeNode* leftHas = lowestCommonAncestor(root->left,p,q);
	TreeNode* rightHas = lowestCommonAncestor(root->right,p,q);

	if ((leftHas && rightHas)||root==p||root==q) return root;
	if (leftHas) return leftHas;
	else return rightHas;
}
posted @ 2022-11-09 14:16  YaosGHC  阅读(28)  评论(0)    收藏  举报