看的代码随想录的解析
236、二叉树的最近公共祖先
基本思想:
自底向上查找,就可以找到公共祖先
回溯就是自底向上
后序遍历是天然的回溯过程,最先处理的一定是叶子节点
具体实现:
找到一个节点,左子树出现节点p,右子树出现节点q(反过来也行),那么该节点就是节点p和q的最近公共祖先。
递归三步:
1、返回值以及参数
返回值:
3种情况,找到最近公共节点,返回最近公共节点
遇到p或q,返回p或q
啥也没找到,返回空
这道题遍历了整棵二叉树,一般这种情况是不需要返回值的,
但是,这道题回溯的过程需要递归函数的返回值做判断
参数:
根节点,p,q
2、确定终止条件
找到p或q,或者空节点,结束递归
3、确定单层递归逻辑
开始了一个很长的解释,,,,,,,,
本题函数有返回值,是因为回溯的过程需要递归函数的返回值做判断,但本题我们依然要遍历树的所有节点。
(1)递归函数有返回值的两种情况
a、搜索一条边的写法
b、搜索整个树的写法
区别:
(2)为什么要遍历整棵树?
因为我们需要对left和right节点进行逻辑处理
而只遍历一条边的写法会直接返回,并不能进行逻辑处理。
用left,right接住左子树和右子树的返回值
(3)逻辑处理
如果left和right都不为空,此时的root就是最近公共节点
如果left为空,right不为空,返回right,
如果right为空,left不为空,返回left。
(4)总结
a、求最小公共祖先,需要从底向上遍历,只能通过后序遍历实现
b、在回溯的过程中,必然要遍历整颗二叉树,即使找到结果了,依然要把其他节点遍历玩,因为要是用递归函数的返回值(left,right)做逻辑判断
代码:
class Solution { public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { return lowestCommonAncestor1(root,p,q); } public TreeNode lowestCommonAncestor1(TreeNode root, TreeNode p, TreeNode q){ if (root == null || root == p || root == q){ return root; } TreeNode left = lowestCommonAncestor1(root.left,p,q); TreeNode right = lowestCommonAncestor1(root.right ,p, q); if (left != null && right != null){ return root; } if (left == null){ return right; } return left; } }
235、二叉搜索树的最近公共祖先
基本思想:
普通二叉树求最近公共祖先需要使用回溯,从底向上来查找,
二叉搜索树就不用了,因为搜索树有序(相当于自带方向),那么只要从上向下遍历就可以了。
具体实现:
1、确定递归函数返回值以及参数
参数:当前节点以及两个节点p,q
返回最近公共祖先
2、确定终止条件:无
3、单层递归逻辑
在遍历二叉搜索树的时候就是寻找区间[p.val, q.val]
如果 cur.val 大于 p.val,同时 cur.val 大于q.val,那么就应该向左遍历(说明目标区间在左子树上)。
需要注意的是此时不知道p和q谁大,所以两个都要判断
本题是标准的搜索一条边的写法,遇到递归函数的返回值,不为空,立刻就返回
代码:
class Solution { public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { if (root.val > p.val && root.val > q.val) return lowestCommonAncestor(root.left, p, q); if (root.val < p.val && root.val < q.val) return lowestCommonAncestor(root.right, p, q); return root; } }
迭代法:
class Solution { public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { while (true) { if (root.val > p.val && root.val > q.val) { root = root.left; } else if (root.val < p.val && root.val < q.val) { root = root.right; } else { break; } } return root; } }