LeetCode 235. 二叉搜索树的最近公共祖先
利用递归和迭代法,每遍历一个节点时判断当前节点是否为空或为目标节点,如果是则返回当前节点,否则递归左子节点和右子节点,然后用两个指针来接受它们所返回的值,根据两个指针是否为空可以判断当前节点的左子树和右子树是否有目标节点。
如果左右指针都不为空说明该节点就是两个目标节点的公共祖先,需要返回当前节点,如果只有一个指针不为空则返回不为空的子树的根节点,还有如果两个指针都为空,说明该节点的子树不存再目标节点,返回空。
以下是代码:
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root == NULL || root == p || root == q) return root;
//递归左右子树,根据返回的信息判断是否存在目标节点
TreeNode* left = lowestCommonAncestor(root -> left, p, q);
TreeNode* right = lowestCommonAncestor(root -> right, p, q);
if(left != NULL && right != NULL) return root;
else if(left == NULL && right != NULL) return right;
else if(right == NULL && left != NULL) return left;
else return NULL;
}
};
LeetCode 701.二叉搜索树中的插入操作
跟据二叉搜索树的特性,如果当前节点的值大于目标值,判断它的左子节点是否为空,如果为空,则将目标值创建成节点插入当前节点的左子节点,如果不为空继续向左递归;如果当前节点的值小于目标节点,同样如果右子节点为空,将目标节点插入右子节点,否则向右递归。
class Solution {
public:
void travel(TreeNode* root, int val) {
//如果当前节点的值大于目标值,并且左节点为空则左节点指针指向用目标值创建的节点,如果不为空继续向左递归
if(root -> val > val) {
if(root -> left == NULL) {
TreeNode* Node = new TreeNode(val);
root -> left = Node;
return;
}
else travel(root -> left, val);
}
//如果当前节点的值小于目标值,并且右节点为空则右指针指向用目标值创建的节点,如果不为空继续向右递归
else if(root -> val < val) {
if(root -> right == NULL) {
TreeNode* Node = new TreeNode(val);
root -> right = Node;
return;
}
else travel(root -> right, val);
}
}
TreeNode* insertIntoBST(TreeNode* root, int val) {
if(root == NULL) {//如果根节点为空,用目标值创建新的节点返回
TreeNode* Node = new TreeNode(val);
return Node;
}
travel(root, val);
return root;
}
};
LeetCode 450.删除二叉搜索树中的节点
删除节点是比较麻烦的一个,也需要用递归和迭代。
找目标节点时,要用递归,找到后删除完返回时需要用到迭代去梳理各节点之间的链接。
首先需要找到目标节点,然后根据以下几种情况分别处理;
一、目标左右子节点都为空时,可以直接删除目标节点。
二、目标左右子节点中有一个为空时,将目标节点删除,然后返回它不为空的子节点。
三、目标左右子节点都不为空时,根据二叉搜索树的特性,目标节点左子树中最大的那个值必定小于右子树最小的值(右子树最左下端的那个节点),所以只需将左子树放到右子树最左下端的做标本即可。然后返回右子树的根节点。
向左递归时,要用当前节点的左指针去接收,同样向右递归时,要用右指针去接收。
然后返回当前的节点。
class Solution {
public:
TreeNode* travel (TreeNode *root, int key) {
if(root == NULL) NULL;//如果当前节点为空直接返回NULL
else if(root -> val == key) {//找到目标节点
if(root -> left == NULL && root -> right == NULL) {//目标节点的左右子节点都为空是可直接删除然后返回空
delete root;
return NULL;
}
//如果左右子节点中有一个为空,将目标节点删除然后返回不为空的那个节点
else if(root -> left == NULL && root -> right != NULL) {
TreeNode* Node = root;
root = root -> right;
delete Node;
return root;
} else if(root -> left != NULL && root -> right == NULL) {
TreeNode* Node = root;
root = root ->left;
delete Node;
return root;
} else {//如果都不为空,将左子树放到右子树最左下断节点的左下方,然后删除目标节点返回右子节点
TreeNode* Node = root -> right;
while(Node -> left != NULL) {
Node = Node -> left;
}
Node -> left = root -> left;
Node = root;
root = root -> right;
delete Node;
return root;
}
}
else {
//向左递归时用左指针去接受返回的值,向右递归相同
root -> left = travel(root -> left, key);
root -> right = travel(root -> right, key);
}
return root; //记得处理完所有事后返回根节点
}
TreeNode* deleteNode(TreeNode* root, int key) {
return travel(root, key);
}
};