235. 二叉搜索树的最近公共祖先
上一个是介绍了普通二叉树的最近公共祖先的问题。
二叉搜索树的特点:二叉搜索树(Binary Search Tree, BST)是一种每个节点的左子树所有节点值均小于该节点值、右子树所有节点值均大于该节点值的二叉树。
思想:判断p,q和当前节点值的关系,3种关系,都小于,都大于,一个大于一个小于分别进行操作。
递归三部曲
确定递归函数的参数和返回值:参数就是root, p, q,返回值类型是TreeNode*,返回的最近公共祖先。
确定终止条件:
如果root==NULL return NULL;
确定单层递归的逻辑:都小于,TreeNode* left = traversal(root->left, p, q); if left != NULL return left;//left不为NULL就说明找到了最近公共祖先直接原封不动向上传递就可以,这个和下面的判断都是起到了一个传递结果的作用。
都大于,TreeNode* right = traversal(root->right, p, q); if right != NULL return right;
else//也就是一个大于一个小于直接返回当前的root(就是最近公共祖先),然后一层一层向上传递结果就可以啦。
下面是C++,JAVA和Python的代码:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
// //递归法
// if(root==NULL) return NULL;
// if(root->val > p->val && root->val > q->val){
// TreeNode* left = lowestCommonAncestor(root->left, p, q);
// if(left!=NULL) return left;
// }
// if(root->val < p->val && root->val < q->val){
// TreeNode* right = lowestCommonAncestor(root->right, p, q);
// if(right!=NULL) return right;
// }
// return root;
//下面是迭代法,对于二叉搜索树来说它的方向是确定的
while(root){
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 return root;
}
return NULL;
}
};
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
// //递归法
// if(root.val > p.val && root.val > q.val){
// TreeNode left = lowestCommonAncestor(root.left, p, q);
// if(left!=null) return left;
// }
// if(root.val < p.val && root.val < q.val){
// TreeNode right = lowestCommonAncestor(root.right, p, q);
// if(right!=null) return right;
// }
// return root;
// 递归法
while(root!=null){
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 return root;
}
return null;
}
}
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def lowestCommonAncestor(self, root, p, q):
"""
:type root: TreeNode
:type p: TreeNode
:type q: TreeNode
:rtype: TreeNode
"""
# # 下面是递归法
# if root == None:
# return None
# if(root.val > p.val and root.val > q.val):
# left = self.lowestCommonAncestor(root.left, p, q)
# if left is not None:
# return left
# elif(root.val < p.val and root.val < q.val):
# right = self.lowestCommonAncestor(root.right, p, q)
# if right is not None:
# return right
# else:
# return root
#迭代法
while root is not None:
if root.val > p.val and root.val > q.val:
root = root.left
elif root.val < p.val and root.val < q.val:
root = root.right
else:
return root
参考文章
701.二叉搜索树中的插入操作
关键: 在二叉搜索树中插入任意一个节点都可以在叶子节点找到它的位置。
因为在叶子节点插入很简单,只要找到要插入的叶子节点的位置比较大小来判断插入到这个叶子节点的左孩子还是右孩子就可以。然后直接赋值。
递归三部曲
确定递归函数的参数和返回值:root,val。返回值是进行插入操作之后的二叉树,TreeNode*。
确定终止条件:
如果root==NULL,我们就定义新的节点。TreeNode* node = new TreeNode(val); return node;(我们是不断递归找到合适的位置,如果当前节点为NULL说明我们找到了要插入的位置,但是这个节点为NULL,我们在当前节点这里是无法获得当前节点的父节点信息的,就是无法进行赋值操作,只能将新节点传递到上一层进行赋值操作)
确定单层递归的逻辑:这里进行一个赋值的操作。
if(valval)就插入到左节点root->left = insert(root->left,val);//这里接住函数的返回值
if(val>root->val)就插入到左节点root->right = insert(root->right,val);//这里接住函数的返回值,然后连接。
否则就return root;//
下面是C++,JAVA和Python的代码:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* insertIntoBST(TreeNode* root, int val) {
if(root==NULL){
TreeNode* node = new TreeNode(val);//递归到空了说明到对应的叶子节点的子节点,也就是我们要插入的位置
return node;//定义一个新的节点返回给上一层操作
}
if(val < root->val){
root->left = insertIntoBST(root->left, val);//递归,如果目标值比根节点的值小就从左子树中寻找适合的叶子节点作为插入的位置
}
if(val > root->val){
root->right = insertIntoBST(root->right, val);
}
return root;
}
};
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public TreeNode insertIntoBST(TreeNode root, int val) {
if(root == null){
TreeNode node = new TreeNode(val);//定义新的节点
return node;
}
if(val < root.val){
root.left = insertIntoBST(root.left, val);
}
if(val > root.val){
root.right = insertIntoBST(root.right, val);
}
return root;
}
}
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def insertIntoBST(self, root, val):
"""
:type root: Optional[TreeNode]
:type val: int
:rtype: Optional[TreeNode]
"""
if root == None:
node = TreeNode(val)
return node
if val > root.val:
root.right = self.insertIntoBST(root.right, val)
if val < root.val:
root.left = self.insertIntoBST(root.left, val)
return root
参考文章
450.删除二叉搜索树中的节点
如果找到了要删除的节点分为4种情况:
- 要删除的节点为叶子节点。左空右空。
- 要删除的节点左不空,右空。
- 要删除的节点左空,右不空。
- 要删除的节点左不空,右不空。(最复杂)
递归三部曲
确定递归函数的参数和返回值:root,key。返回值是进行删除操作之后的二叉树,TreeNode*。
确定终止条件:
如果root==NULL return NULL;//没有找到要删除的值
如果找到了要删除的值:
4种情况分别操作。注意递归中递归找到这个要删除的节点是不能立即进行删除操作的,要返回替换原来节点的二叉树节点(比如如果删除叶子节点就是NULL,如果删除左不为空右为空的返回当前节点的左子树,如果删除左为空右不为空的返回当前节点的右子树,如果删除的是左右不为空的就是返回操作后的当前节点的右子树)。
确定单层递归的逻辑:这里进行一个赋值的操作。
if(keyval)说明删除的节点位于当前节点的左子树 root->left = delete(root->left,key);//这样就是连接上了返回值。(完成删除操作和插入元素一样不仅在要操作的节点上生成或者更新了连接,每一个经过的路径的连接也重新连接了一遍)
if(key>root->val)说明删除的节点位于当前节点的右子树 root->right = delete(root->right,key);//这样就是连接上了返回值。
return root;//返回根节点
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
//终止条件
if(root==NULL) return NULL;//没有发现要删除的节点或者root本身为NULL,返回NULL
if(root->val==key){//找到要删除的节点分4种情况讨论
if(root->left==NULL && root->right==NULL){
return NULL;//如果找到的要删除的节点是叶子节点返回NULL,传回给上一层处理,将这个返回值赋值给上一层的左/右孩子,因为这里无法得到叶子节点的父节点也不知道是左还是右节点
}else if(root->left != NULL && root->right == NULL){
return root->left;//删除只有一个左右孩子的节点的时候只需要将这个节点的孩子赋值给该节点父节点的左/右孩子就可以
}else if(root->left == NULL && root->right != NULL){
return root->right;
}else{//左右孩子都不为空,遵顼同一种处理方式
TreeNode* cur = root->right;
while(cur->left!=NULL){
cur = cur->left;
}
cur->left = root->left;//将该节点的左子树移动到右子树种最左的节点的左孩子位置
return root->right;//该节点的左子树移动到右子树中了,只移动右子树就可以
}
}
//下面是递归处理逻辑
if(key < root->val){root->left=deleteNode(root->left,key);}
if(key > root->val){root->right=deleteNode(root->right,key);}
return root;
}
};
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
if(root==null) return null;//没找到要删除的节点
if(root.val == key){
if(root.left == null && root.right == null){
return null;//处理叶子节点
}
else if(root.left==null && root.right != null){
return root.right;
}
else if(root.left!=null && root.right == null){
return root.left;
}
else{
TreeNode cur = root.right;
while(cur.left!=null){
cur = cur.left;
}
cur.left = root.left;
return root.right;
}
}
if(key < root.val){ root.left = deleteNode(root.left, key);}
if(key > root.val){ root.right = deleteNode(root.right, key);}
return root;
}
}
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def deleteNode(self, root, key):
"""
:type root: Optional[TreeNode]
:type key: int
:rtype: Optional[TreeNode]
"""
if root == None:
return None
if(root.val == key):#找到了要删除的节点
if(root.left == None and root.right == None):
return None
elif root.left == None and root.right != None:
return root.right
elif root.left != None and root.right == None:
return root.left
else:
cur = root.right
while(cur.left!=None):
cur = cur.left
cur.left = root.left
return root.right
#单层递归逻辑
if key < root.val:
root.left = self.deleteNode(root.left, key)
if key > root.val:
root.right = self.deleteNode(root.right, key)
return root