第六章二叉树part08
235. 二叉搜索树的最近公共祖先
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先.
思路:与一般二叉树寻找最近公共祖先不同,二叉搜索树可以直接通过节点值来判断。可以从上到下进行遍历,判断遍历节点值在两个节点值之间即为两个指定节点的最近公共祖先。
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root->val>p->val&&root->val>q->val) return lowestCommonAncestor(root->left,p,q);
if(root->val<p->val&&root->val<q->val) return lowestCommonAncestor(root->right,p,q);
return root;
}
701. 二叉搜索树中的插入操作
给定二叉搜索树(BST)的根节点 root
和要插入树中的值 value
,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 ,新值和原始二叉搜索树中的任意节点值都不同。
注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回 任意有效的结果 。
思路:通过节点数值与根节点数值比较,从而找到合适的位置并插入。注意根节点为空的情况。
class Solution {
public:
void traversal(TreeNode* root,int val){
if(root->left==NULL&&val<root->val) root->left=new TreeNode(val);
if(root->right==NULL&&val>root->val) root->right=new TreeNode(val);
if(val<root->val) traversal(root->left,val);
if(val>root->val) traversal(root->right,val);
}
TreeNode* insertIntoBST(TreeNode* root, int val) {
if(root==NULL){
root=new TreeNode(val);
return root;
}
traversal(root,val);
return root;
}
};
450. 删除二叉搜索树中的节点
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
一般来说,删除节点可分为两个步骤:
- 首先找到需要删除的节点;
- 如果找到了,删除它。
思路:找到需要删除的节点之后分四种情况处理(具体见注释),写完之后发现一些测试用例不通过(删除节点为根节点),因为是通过额外节点记录处理节点的父节点,所以如果删除节点为根节点则其没有父节点无法处理,所以增加了一个虚根节点并设置其不为空,可以ac.
题解中遇到空节点就完全不做处理,直接跳过,条件判断中加了判断空节点条件
写完有一个疑惑:这里的parent节点指向的为什么是左右子节点的父节点,而不是像中序遍历中指向前一个节点?????
因为他不是中序遍历啊完全,是根据值的大小决定下一个遍历的子节点是左还是右!
class Solution {
public:
TreeNode* parent=NULL;
void traversal(TreeNode* root,int key){
if(root!=NULL&&root->val==key){ //中
//删除节点没有子节点,值对比判断该节点为父节点的左/右节点
if(root->left==NULL&&root->right==NULL){
if(key<parent->val) parent->left=NULL;
else parent->right=NULL;
root=NULL;
}
//删除节点右子节点为空
else if(root->left!=NULL&&root->right==NULL){
if(key<parent->val) parent->left=root->left;
else parent->right=root->left;
root=NULL;
}
//删除节点左子节点为空
else if(root->left==NULL&&root->right!=NULL){
if(key<parent->val) parent->left=root->right;
else parent->right=root->right;
root=NULL;
}
//删除节点左右节点均不为空,将删除节点右子节点上移,将左子节点移到原右子节点的最左子节点
else{
TreeNode* left=root->left;
if(key<parent->val) parent->left=root->right;
else parent->right=root->right;
TreeNode* cur=root->right;
//找到最左子节点
while(cur->left){
cur=cur->left;
}
cur->left=left;
root=NULL;
}
}
parent=root;
if(root!=NULL&&root->val>key) traversal(root->left,key); //左
if(root!=NULL&&root->val<key) traversal(root->right,key); //右
}
TreeNode* deleteNode(TreeNode* root, int key) {
//设置虚根节点,避免要删除节点为根节点情况
TreeNode* dummyRoot=new TreeNode(200000);
dummyRoot->left=root;
if(root==NULL) return NULL;
traversal(dummyRoot,key);
return dummyRoot->left;
}
};
第三题感想:其实思路是很明显的,就是一些空节点判断的位置有所模糊,遇到这种题就应该直接code然后再慢慢debug,花了较多时间因为一直怀疑自己的做法到底能不能解出来,试就完了呗。