代码随想录训练营Day22 | Leetcode 235、701、450
一、235 二叉搜索树的最近公共祖先
题目链接:235 二叉搜索树的最近公共祖先
核心:明确二叉搜索树的性质,即如果某一节点值大于p且小于q,那么该节点即为p和q的最近公共祖先。
(1)若某节点为空,或等于p,或等于q,均直接返回该节点即可;
(2)若某一节点值均大于p和q,说明p和q都在该节点的左子树上,得从左子树遍历确定最近公共祖先;
(3)若某一节点值均小于p和q,说明p和q都在该节点的右子树上,得从右子树遍历确定最近公共祖先。
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
//递归法:
if(!root || root==p || root==q)
return root; //node为空则说明不存在公共祖先,node为p或q说明node为公共祖先
if(root->val > p->val && root->val > q->val)
{//说明得在左子树遍历寻找
TreeNode* left=lowestCommonAncestor(root->left,p,q);
if(left)
return left; //left不为空说明已经在左子树遍历过程中找到了公共祖先
}
else if(root->val < p->val && root->val < q->val)
{//说明需要在右子树遍历寻找
TreeNode* right=lowestCommonAncestor(root->right,p,q);
if(right)
return right;
}
//root->val >p->val && root->val <q->val,说明root在p、q中间,即返回root
return root;
}
二、701 二叉搜索树中的插入操作
题目链接:701 二叉搜索树中的插入操作
核心:要理解遇到空节点时就进行插入操作!
比较待插入元素和根节点值,确定是在左子树插入还是在右子树插入。
最后一行返回root的理解不够深入!
TreeNode* insertIntoBST(TreeNode* root, int val) {
//递归法:注意使用二叉搜索树的特性,以及遍历到null时将节点插入,最后返回插入的节点
if(!root)
{//root==nullptr,插入节点
TreeNode* node=new TreeNode(val);
return node; //node链接到父节点root上
}
//根据二叉搜索树根节点与左子树和右子树的大小关系,确定遍历哪一边,搜索树一定是遍历一条边
if(root->val > val)
root->left=insertIntoBST(root->left,val);
if(root->val < val)
root->right=insertIntoBST(root->right,val);
return root; //为何此处返回root?
}
三、450 删除二叉搜索树中的节点
题目链接:450 删除二叉搜索树中的节点
核心:要理解针对待删除节点的左右孩子的不同情况进行不同操作
(1)待删除节点为空,则无需删除,直接返回该节点;
(2)找到待删除节点了,但需要根据不同的情况进行处理:
第一,待删除节点的左右孩子都为空,直接删除返回空;
第二,待删除节点的左右孩子其一不为空,其一为空,删除该节点后不为空的节点成为根节点,故返回不为空的节点;
第三,待删除节点的左右孩子都不为空(最特别),此时删除节点后,原左孩子需移位到原右孩子的最左边节点,因此先找到待删除节点的右孩子的最左边节点,然后令待删除节点的左孩子移到已找到的最左边节点上,最后删除节点后,原右孩子成为新的根节点。
(3)未找到待删除节点,则需要递归寻找待删除节点,根据二叉搜索树的性质,无需搜索整棵树,只需要搜索一边即可。
最后一行的返回root理解不深?
TreeNode* deleteNode(TreeNode* root, int key) {
//递归法:
//1.当前节点为空,说明没找到要删除的节点
if(root==nullptr)
return root;
if(root->val == key)
{//已找到要删除的节点
if(!root->left && !root->right)
{//2.待删除节点的左右孩子都为空,直接删除该节点返回空即可
delete root;
return nullptr;
}
else if(root->left && !root->right)
{//3.待删除节点的左孩子不为空,右孩子为空,那么删除该节点后左孩子成为根节点
TreeNode* node=root->left;
delete root;
return node;
}
else if(!root->left && root->right)
{//4.待删除节点的左孩子为空右孩子不为空,则删除该节点后右孩子成为根节点
TreeNode* node=root->right;
delete root;
return node;
}
else
{//5.待删除节点的左右孩子都不为空,则删除该节点后左孩子需移位到右孩子的最左边节点
TreeNode* cur=root->right; //cur寻找待删除节点右孩子的最左边节点
while(cur->left)
{//当cur的左孩子为空时退出循环,此时cur即最左边节点
cur=cur->left;
}
cur->left=root->left; //待删除节点左孩子移到cur的左孩子处
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; //此处返回root不理解?
}