建网站 深圳,吴江公司网站建设电话,淄博展厅设计公司,创造网站的最简单 软件是哪个题目#xff1a;
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为#xff1a;“对于有根树 T 的两个结点 p、q#xff0c;最近公共祖先表示为一个结点 x#xff0c;满足 x 是 p、q 的祖先且 x 的深度尽可能大#xff08;一…题目
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为“对于有根树 T 的两个结点 p、q最近公共祖先表示为一个结点 x满足 x 是 p、q 的祖先且 x 的深度尽可能大一个节点也可以是它自己的祖先。”
例如给定如下二叉搜索树: root [6,2,8,0,4,7,9,null,null,3,5]
示例 1: 输入: root [6,2,8,0,4,7,9,null,null,3,5], p 2, q 8 输出: 6 解释: 节点 2 和节点 8 的最近公共祖先是 6。
示例 2: 输入: root [6,2,8,0,4,7,9,null,null,3,5], p 2, q 4 输出: 2 解释: 节点 2 和节点 4 的最近公共祖先是 2, 因为根据定义最近公共祖先节点可以为节点本身。
说明:
所有节点的值都是唯一的。p、q 为不同节点且均存在于给定的二叉搜索树中。 思路
做过二叉树236. 二叉树的最近公共祖先 中等题目的同学应该知道利用回溯从底向上搜索遇到一个节点的左子树里有p右子树里有q那么当前节点就是最近公共祖先。
那么本题是二叉搜索树二叉搜索树是有序的那得好好利用一下这个特点。
因为是有序树所以 如果 中间节点是 q 和 p 的公共祖先那么 中节点的数组 一定是在 [p, q]区间的。即 中节点 p 中节点 q 或者 中节点 q 中节点 p。
那么只要从上到下去遍历遇到 cur节点是数值在[p, q]区间中则一定可以说明该节点cur就是p 和 q的公共祖先。 那问题来了一定是最近公共祖先吗
如图我们从根节点搜索第一次遇到 cur节点是数值在[q, p]区间中即 节点5此时可以说明 q 和 p 一定分别存在于 节点 5的左子树和右子树中。
此时节点5是不是最近公共祖先 如果 从节点5继续向左遍历那么将错过成为p的祖先 如果从节点5继续向右遍历则错过成为q的祖先。
所以当我们从上向下去递归遍历第一次遇到 cur节点是数值在[q, p]区间中那么cur就是 q和p的最近公共祖先。
理解这一点本题就很好解了。
而递归遍历顺序本题就不涉及到 前中后序了这里没有中节点的处理逻辑遍历顺序无所谓了。
直接按照指定的方向就可以找到为最近公共祖先的节点而且不需要遍历整棵树找到结果直接返回
递归法
确定递归函数返回值以及参数
参数就是当前节点以及两个结点 p、q。
返回值是要返回最近公共祖先所以是TreeNode * 。
代码如下
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q)确定终止条件
遇到空或者已经在[p,q]或[q,p]区间内返回就可以了。
代码如下
if((root NULL) || (root-val p-val root-val q-val) || (root-val p-val root-val q-val)) return root;确定单层递归的逻辑
在遍历二叉搜索树的时候就是寻找区间[p-val, q-val]注意这里是左闭又闭
那么如果 cur-val 大于 p-val同时 cur-val 大于q-val那么就应该向左遍历说明目标区间在左子树上。
需要注意的是此时不知道p和q谁大所以两个都要判断。
如果 cur-val 小于 p-val同时 cur-val 小于 q-val那么就应该向右遍历目标区间在右子树。
本题就是标准的搜索一条边的写法遇到递归函数的返回值如果不为空立刻返回。
代码如下
// 若p和q在当前值的左子树中则往左搜索
if(root-val p-val root-val q-val){TreeNode* left lowestCommonAncestor(root-left, p, q);if(left ! NULL) return left; // 找到则退出递归
}// 若p和q在当前值的右子树中则往右搜索
else if(root-val p-val root-val q-val){TreeNode* right lowestCommonAncestor(root-right, p, q);if(right ! NULL) return right; // 找到则退出递归
}return NULL;迭代法
对于二叉搜索树的迭代法应该在二叉树700. 二叉搜索树中的搜索 简单就了解了。
利用其有序性迭代的方式还是比较简单的解题思路在递归中已经分析了。 代码
递归法
class Solution {
public:TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {// 当前值为空或符合条件直接返回if((root NULL) || (root-val p-val root-val q-val) || (root-val p-val root-val q-val)) return root;// 若p和q在当前值的左子树中则往左搜索if(root-val p-val root-val q-val){TreeNode* left lowestCommonAncestor(root-left, p, q);if(left ! NULL) return left; // 找到则退出递归}// 若p和q在当前值的右子树中则往右搜索else if(root-val p-val root-val q-val){TreeNode* right lowestCommonAncestor(root-right, p, q);if(right ! NULL) return right; // 找到则退出递归}return NULL;}
};迭代法
class Solution {
public:TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {while(root ! NULL){// 当前值符合条件直接返回if((root-val p-val root-val q-val) || (root-val p-val root-val q-val)) return root;// 若p和q在当前值的左子树中则往左搜索else if(root-val p-val root-val q-val){root root-left;}// 若p和q在当前值的右子树中则往右搜索else if(root-val p-val root-val q-val){root root-right;}}return NULL;}
};总结
对于二叉搜索树的最近祖先问题其实要比普通二叉树公共祖先问题简单的多。
不用使用回溯二叉搜索树自带方向性可以方便的从上向下查找目标区间遇到目标区间内的节点直接返回。
最后给出了对应的迭代法二叉搜索树的迭代法甚至比递归更容易理解也是因为其有序性自带方向性按照目标区间找就行了。 参考
代码随想录