如果利用普通二叉树的方法,就是利用后序遍历回溯从低向上搜索,遇到左子树有p,右子树有q,那么当前结点就是最近公共祖先。本题是二叉搜索树,所以说是有序的,一定能够简化上面的方法。如果中间节点是p和q的公共祖先,那么他一定是在p和q区间的,即中节点 > p && 中节点 < q 或者 中节点 > q && 中节点 < p。所以在每次遍历时,都加上这个判断条件会比较好。递归代码如下:
class Solution {
private:
TreeNode* traversal(TreeNode* cur, TreeNode* p, TreeNode* q) {
if (cur == NULL) return cur;
// 中
if (cur->val > p->val && cur->val > q->val) { // 左
TreeNode* left = traversal(cur->left, p, q);
if (left != NULL) {
return left;
}
}
if (cur->val < p->val && cur->val < q->val) { // 右
TreeNode* right = traversal(cur->right, p, q);
if (right != NULL) {
return right;
}
}
return cur;
}
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
return traversal(root, 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);
} else if (root->val < p->val && root->val < q->val) {
return lowestCommonAncestor(root->right, p, q);
} else return root;
}
};
?因为是二叉搜索树,所以迭代法也很简单,一般二叉搜索树迭代法都比普通二叉树简单,因为这棵树是有序的:
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
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;
}
};
进行二叉搜索树的插入操作并不需要调整二叉树的结构,因为特殊性,每次插入的结点都能插入到叶子上面,所以递归的方法就比较简单了
class Solution {
public:
TreeNode* insertIntoBST(TreeNode* root, int val) {
if (root == NULL) {
TreeNode* node = new TreeNode(val);
return node;
}
if (root->val > val) root->left = insertIntoBST(root->left, val);
if (root->val < val) root->right = insertIntoBST(root->right, val);
return root;
}
};
?本题也可以利用迭代法:
class Solution {
public:
TreeNode* insertIntoBST(TreeNode* root, int val) {
//如果为空节点此时直接进行插入(说明是一颗空树)
if (root == NULL) {
TreeNode* node = new TreeNode(val);
return node;
}
TreeNode* cur = root; //记录当前的结点
TreeNode* parent = root; // 这个很重要,需要记录上一个节点,否则无法赋值新节点
while (cur != NULL) {
parent = cur; //上一个结点接连等于当前结点,之后当前结点变动
if (cur->val > val) cur = cur->left;
else cur = cur->right;
}
//此时遍历到空节点了,也就是要插入val的位置
TreeNode* node = new TreeNode(val);
if (val < parent->val) parent->left = node;// 此时是用parent节点的进行赋值
else parent->right = node;
return root;
}
};
注意此时有些情况就需要改变二叉树的结构了,因为删除的并不一定是叶子节点。
class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
if(root == nullptr) return root; //如果是空节点直接返回,说明没有找到要删除的节点
if(root->val == key){
//要删除的节点为叶子结点
if(root->left==nullptr&&root->right==nullptr){
delete root;
return nullptr;
}
//要删除的节点左空右不空
if(root->left==nullptr&&root->right!=nullptr){
TreeNode* node = root->right;
delete root;
return node;
}
//要删除的结点左不空右空
if(root->left!=nullptr&&root->right==nullptr){
TreeNode* node = root->left;
delete root;
return node;
}
//要删除的节点左右都不空,让右面的结点顶替他(当然左面的也可以,这里只写一种)
if(root->left!=nullptr&&root->right!=nullptr){
TreeNode* cur = root->right;
while(cur->left) cur = cur->left;
cur->left=root->left;
TreeNode* tmp = root;
root = root->right;
delete tmp;
return root;
}
}
if(root->val > key) root->left = deleteNode(root->left, key);
if(root->val < key) root->right = deleteNode(root->right, key);
return root;
}
};
?
这里我在介绍一种通用的删除,普通二叉树的删除方式(没有使用搜索树的特性,遍历整棵树),用交换值的操作来删除目标节点。
代码中目标节点(要删除的节点)被操作了两次:
class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
if (root == nullptr) return root;
if (root->val == key) {
if (root->right == nullptr) { // 这里第二次操作目标值:最终删除的作用
return root->left;
}
TreeNode *cur = root->right;
while (cur->left) {
cur = cur->left;
}
swap(root->val, cur->val); // 这里第一次操作目标值:交换目标值其右子树最左面节点。
}
root->left = deleteNode(root->left, key);
root->right = deleteNode(root->right, key);
return root;
}
};
?迭代法:
class Solution {
private:
// 将目标节点(删除节点)的左子树放到 目标节点的右子树的最左面节点的左孩子位置上
// 并返回目标节点右孩子为新的根节点
// 是动画里模拟的过程
TreeNode* deleteOneNode(TreeNode* target) {
if (target == nullptr) return target;
if (target->right == nullptr) return target->left;
TreeNode* cur = target->right;
while (cur->left) {
cur = cur->left;
}
cur->left = target->left;
return target->right;
}
public:
TreeNode* deleteNode(TreeNode* root, int key) {
if (root == nullptr) return root;
TreeNode* cur = root;
TreeNode* pre = nullptr; // 记录cur的父节点,用来删除cur
while (cur) {
if (cur->val == key) break;
pre = cur;
if (cur->val > key) cur = cur->left;
else cur = cur->right;
}
if (pre == nullptr) { // 如果搜索树只有头结点
return deleteOneNode(cur);
}
// pre 要知道是删左孩子还是右孩子
if (pre->left && pre->left->val == key) {
pre->left = deleteOneNode(cur);
}
if (pre->right && pre->right->val == key) {
pre->right = deleteOneNode(cur);
}
return root;
}
};