LeetCode235. 二叉搜索树的最近公共祖先
递归相较于普通二叉树的最近公共祖先,思路还是简单的,代码如下:
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root==nullptr) return nullptr;
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;
}
};
迭代法思路也非常简单,代码如下:
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{
break;
}
}
return root;
}
};
LeetCode701.二叉搜索树中的插入操作
本题先用迭代法可以较轻松做出来,只需要记录前一个节点就可以,代码如下:
class Solution {
public:
TreeNode* insertIntoBST(TreeNode* root, int val) {
if(root==nullptr) return new TreeNode(val);
TreeNode* pre;
TreeNode* tmp = root;
while(tmp){
if(tmp->val<val){
pre = tmp;
tmp = tmp->right;
}else if(tmp->val>val){
pre = tmp;
tmp = tmp->left;
}
}
if(pre->val>val) pre->left = new TreeNode(val);
else pre->right = new TreeNode(val);
return root;
}
};
用递归的方法比较巧妙,比较难想到可以直接将节点不停的向上返回,如果是空节点,则返回新插入的节点,让上一层递归的left或right接住就可以了,那么如果不是空节点,这个思路也是适用的,代码如下:
class Solution {
public:
TreeNode* insertIntoBST(TreeNode* root, int val) {
if(root==nullptr){
return new TreeNode(val);
}
if(root->val>val){
root->left = insertIntoBST(root->left,val);
}else if(root->val<val){
root->right = insertIntoBST(root->right,val);
}
return root;
}
};
LeetCode450.删除二叉搜索树中的节点
这道题需要考虑清楚5种情况
1、没有找到删除节点
2、删除节点左右孩子都为空
3、删除节点左孩子为空,右孩子不为空
4、删除节点左孩子不为空,右孩子为空
5、删除节点左右孩子都不为空:需要找左孩子或右孩子来顶替被删除节点,找谁逻辑都是类似的,这里以找右孩子为例,那么被删除节点的左孩子需要找地方放,就只能放在被删除节点右孩子的最左孩子的左孩子处(说的有点绕,可以画图就能想通)
以上五种情况写终止条件时,均可以返回具体的左右子树的节点,然后在上一层递归中会用根节点的左右子树来接住,思路也是很巧妙地。
注:C++应涉及内存释放的操作,即在每一步返回前先用临时变量接住要返回的变量,在delete掉要删除的节点,再返回临时变量。
class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
if(root==nullptr) return nullptr;
if(root->val==key){
if(!root->left && !root->right){
return nullptr;
}else if(!root->left && root->right){
return root->right;
}else if(root->left && !root->right){
return root->left;
}else{
TreeNode* cur = root->right;
while(cur->left) cur = cur->left;
cur->left = root->left;
return root->right;
}
}
if(root->val>key) root->left = deleteNode(root->left,key);
else 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;
}
};
删除普通二叉树节点:
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;
}
};