1.二叉搜索树的最近公共祖先
题目链接/文章讲解: 代码随想录
代码: (递归法)
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){
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 != 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;
}
};
2.二叉搜索树中的插入操作
题目链接/文章讲解: 代码随想录
代码:(递归法)
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);
}else{
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* parent = NULL;
TreeNode* cur = root;
// 找到合适的插入位置的parent结点
while(cur != NULL){
parent = cur;
if(cur->val > val){
cur = cur->left;
}else{
cur = cur->right;
}
}
TreeNode* node = new TreeNode(val);
if(parent->val > val){
parent->left = node;
}else{
parent->right = node;
}
return root;
}
};
3.删除二叉搜索树中的结点
题目链接/文章讲解:代码随想录
代码:
class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
// 递归出口
// 情况1:没有找到目标结点
if(root == NULL) return NULL;
if(root->val == key){
// 情况2:目标结点的左右孩子都为空
// 情况3:目标结点的左孩子为空
if(root->left == NULL) {
auto tmp = root->right;
delete root;
return tmp;
// 情况4:目标结点的右孩子为空
}else if(root->right == NULL) {
auto tmp = root->left;
delete root;
return tmp;
}else{
// 情况5:目标结点的左右孩子都不为空
// 找右子树最左的孩子
TreeNode* cur = root->right;
while(cur->left){
cur = cur->left;
}
// 将目标结点的左孩子赋值给我们在右子树里找到的最小结点的左孩子
cur->left = root->left;
TreeNode* tmp = root;
root = root->right;
delete tmp;
return root;
}
}else if(root->val > key){
root->left = deleteNode(root->left,key);
}else{
root->right = deleteNode(root->right,key);
}
return root;
}
};
思路:
首先要想到删除时的五种情况:1.没有找到要删除的结点;2.删除结点是叶子结点;3.删除结点左孩子为空;4.删除结点右孩子为空;5.删除结点的左右孩子都不为空。
第五种情况:找到右子树中最小的结点(就是利用搜索树的特性,一直找结点的左孩子),将左子树赋值给这个最小结点。最后用右子树代替当前子树。
其实想明白了就不难。