LeetCode 235 二叉搜索树的最近公共祖先
题目链接:https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-search-tree/
思路:
因为二叉搜索树是有序的,所以如果 当前节点cur的值是在[p,q](假设p的值大于q,实际上都有可能),那么可以说明当前的cur是它们的最近公共祖先。前提是从上往下遍历。
代码:
递归法
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
private:
TreeNode* traversal(TreeNode *root,TreeNode *p,TreeNode *q)
{
if(root==nullptr) return root;
if(root->val>p->val&&root->val>q->val)
{
TreeNode *left = traversal(root->left,p,q);
// 因为只要搜索到某一边存在即可,不用搜索整棵树,所以此处要返回
if(left)
return left;
}
if(root->val<p->val&&root->val<q->val)
{
TreeNode *right = traversal(root->right,p,q);
// 因为只要搜索到某一边存在即可,不用搜索整棵树,所以此处要返回
if(right)
return right;
}
return root;
}
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
return traversal(root,p,q);
}
};
迭代法
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
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 nullptr;
}
};
总结
自己想的时候没想明白应该如何使用二叉搜索树是有序的这一特点。
LeetCode 701 二叉搜索树中的插入操作
题目链接:https://leetcode.cn/problems/insert-into-a-binary-search-tree/
思路:
在二叉搜索树里,插入的节点都可以放到叶子节点处。采用这样的思想,就不用对二叉搜索树进行重构并且保留了二叉搜索树的有序性。
代码:
递归法
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* insertIntoBST(TreeNode* root, int val) {
// 当root不存在,说明此时已经遍历到了叶子节点处,所以应该在这里插入我们想插入的节点
if(root==nullptr)
{
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;
}
};
迭代法-自写
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* insertIntoBST(TreeNode* root, int val) {
if(root==nullptr)
{
root = new TreeNode(val);
return root;
}
TreeNode *cur = root;
while(cur)
{
if(cur->val<val)
{
if(cur->right==nullptr)
{
cur->right = new TreeNode(val);
return root;
}
else
cur = cur->right;
}
else
{
if(cur->left==nullptr)
{
cur->left = new TreeNode(val);
return root;
}
else
cur = cur->left;
}
}
return root;
}
};
总结
在二叉搜索树中插入节点,只要将节点放到叶子节点处即可。
LeetCode 450 删除二叉搜索树中的节点
题目链接:https://leetcode.cn/problems/delete-node-in-a-bst/
思路:
有五种情况:
1、二叉搜索树中没有key
2、二叉搜索树中有key
(1)左子树为空,右子树为空,即叶子节点的值等于key,此时将该叶子节点变成nullptr即可。
(2)左子树不为空,右子树为空,此时将父节点的左子树变成被删节点的左子树即可。
(3)左子树为空,右子树不为空,此时将父节点的右子树变成被删节点的右子树即可。
(4)左子树不为空,右子树不为空,此时将被删节点的左子树转移到被删节点的右子树中左子树的最左边,这样就变成了(3)的情况。
代码:
递归法(左子树不为空,右子树不为空时,将左边接到右边)
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
// 终止条件
// 找到要被删的节点就终止了,所以要在终止条件处进行删除操作
// 情况一:找不到key
if(root==nullptr) return nullptr;
// 情况二:找到key
if(root->val==key)
{
// 1、左右子树为空,即被删节点为叶子节点
if(!root->left&&!root->right)
{
delete root;
return nullptr;
}
// 2、左子树不为空,右子树为空
else if(root->left&&!root->right)
{
TreeNode *temp = root->left;
delete root;
return temp;
}
// 3、左子树为空,右子树不为空
else if(!root->left&&root->right)
{
TreeNode *temp = root->right;
delete root;
return temp;
}
// 4、左子树不为空,右子树不为空
else
{
TreeNode *cur = root->right;
while(cur->left)
cur = cur->left;
cur->left = root->left;
TreeNode *temp = root->right;
delete root;
return temp;
}
}
if(root->val>key) root->left = deleteNode(root->left,key);
if(root->val<key) root->right = deleteNode(root->right,key);
return root;
}
};
递归法(左子树不为空,右子树不为空时,将右边接到左边)
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
// 终止条件
// 找到要被删的节点就终止了,所以要在终止条件处进行删除操作
// 情况一:找不到key
if(root==nullptr) return nullptr;
// 情况二:找到key
if(root->val==key)
{
// 1、左右子树为空,即被删节点为叶子节点
if(!root->left&&!root->right)
{
delete root;
return nullptr;
}
// 2、左子树不为空,右子树为空
else if(root->left&&!root->right)
{
TreeNode *temp = root->left;
delete root;
return temp;
}
// 3、左子树为空,右子树不为空
else if(!root->left&&root->right)
{
TreeNode *temp = root->right;
delete root;
return temp;
}
// 4、左子树不为空,右子树不为空
else
{
TreeNode *cur = root->left;
while(cur->right)
cur = cur->right;
cur->right = root->right;
TreeNode *temp = root->left;
delete root;
return temp;
}
}
if(root->val>key) root->left = deleteNode(root->left,key);
if(root->val<key) root->right = deleteNode(root->right,key);
return root;
}
};
总结
要把每种情况都想清楚,写代码之前要理顺,然后再开始写代码才能事半功倍。
今日总结:
学习了二叉搜索树的插入节点和删除节点。普通二叉树寻找最近公共祖先要从下网上进行回溯,而二叉搜索树寻找最近公共祖先,利用其有序的特性,只要从上往下找到一个值在要找的两个值的区间范围内即可。很是巧妙。