文章目录
- 二叉树例题分享
- [235. 二叉搜索树的最近公共祖先](https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-search-tree/)
- [701. 二叉搜索树中的插入操作](https://leetcode.cn/problems/insert-into-a-binary-search-tree/)
- [108. 将有序数组转换为二叉搜索树](https://leetcode.cn/problems/convert-sorted-array-to-binary-search-tree/)
- [450. 删除二叉搜索树中的节点](https://leetcode.cn/problems/delete-node-in-a-bst/)
二叉树例题分享
235. 二叉搜索树的最近公共祖先
题目
代码
struct TreeNode* lowestCommonAncestor(struct TreeNode* root, struct TreeNode* p,
struct TreeNode* q) {
struct TreeNode* ans = root;
while (ans != NULL) {
if (ans->val > p->val && ans->val > q->val) {
ans = ans->left;
} else if (ans->val < p->val && ans->val < q->val) {
ans = ans->right;
} else {
return ans;
}
}
return ans;
}
题解
本题要求我们找到二叉搜索树中两个节点的最小公共祖先,因为是二叉搜索树,所以实现起来还是比较简单的,因为二叉搜索树的左子树数值一定小于根节点数值小于右子树数值。
多以我们遍历一遍二叉树就可以找到答案:
- 如果ans节点数值同时大于p,q数值,那么p,q一定在ans节点的左边,向左遍历;
- 如果ans节点数值同时小于p,q数值,那么p,q一定在ans节点的右边,向右遍历;
- 如果一大一小,那证明找到了最近公共祖先。
总体来说只要我们知道在什么情况下是最近公共祖先,我们就可以轻松实现本题要求。
701. 二叉搜索树中的插入操作
题目
代码
struct TreeNode* insertIntoBST(struct TreeNode* root, int val) {
struct TreeNode* ans = root;
struct TreeNode* new = (struct TreeNode*)malloc(sizeof(struct TreeNode));
new->left = NULL;
new->right = NULL;
new->val = val;
if (root == NULL)
return new;
while (root) {
if (root->val > val) {
if (root->left != NULL)
root = root->left;
else {
root->left = new;
return ans;
}
} else {
if (root->right != NULL)
root = root->right;
else {
root->right = new;
return ans;
}
}
}
return ans;
}
题解
本题可以使用两种方法去实现:
第一种:
迭代法
迭代法是我在没有看题解情况下完成的。
因为是二叉搜索树,所以我们遍历一次便可以实现。
我们在遍历二叉树的时候,如果本节点的数值大于val,则证明val应该插入到左子树中,反之插入右子树中,我们只需要继续判断本节点的左孩子节点(右孩子节点)是否为空,如果不为空则继续遍历,如果为空则证明该位置就为插入位置。
下面是代码:
struct TreeNode* insertIntoBST(struct TreeNode* root, int val) {
if (root == NULL)
return root;
struct TreeNode* ans = root;
struct TreeNode* new = (struct TreeNode*)malloc(sizeof(struct TreeNode));
new->left = NULL;
new->right = NULL;
new->val = val;
while (root) {
if (root->val > val) {
if (root->left != NULL)
root = root->left;
else {
root->left = new;
return ans;
}
} else {
if (root->right != NULL)
root = root->right;
else {
root->right = new;
return ans;
}
}
}
return ans;
}
第二种:
递归法
- 终止递归是如果遇到了空节点,则证明该位置就应该是插入位置,直接返回新节点接可以了;
- 后面我们考虑一层递归的逻辑,我们判断val与root->val的大小关系,然后继续遍历左孩子节点或右孩子节点(之后会返回),并且用root->left或root->right接住返回值;
- 最后返回root就可以了。
最后的代码是这样的:
struct TreeNode* insertIntoBST(struct TreeNode* root, int val) {
if (root == NULL) {
struct TreeNode* new =
(struct TreeNode*)malloc(sizeof(struct TreeNode));
new->left = NULL;
new->right = NULL;
new->val = val;
return new;
}
if (val > root->val)
root->right = insertIntoBST(root->right, val);
if (val < root->val)
root->left = insertIntoBST(root->left, val);
return root;
}
108. 将有序数组转换为二叉搜索树
题目
代码
struct TreeNode* Traval(int* nums, int left, int right) {
if (left > right)
return NULL;
int mid = (left + right) / 2;
struct TreeNode* root = (struct TreeNode*)malloc(sizeof(struct TreeNode));
root->val = nums[mid];
root->left = Traval(nums, left, mid - 1);
root->right = Traval(nums, mid + 1, right);
return root;
}
struct TreeNode* sortedArrayToBST(int* nums, int numsSize) {
return Traval(nums, 0, numsSize - 1);
}
题解
本题要求我们将给定的升序数组转换成一棵平衡二叉搜索树。
我们的思路就是每次都将数组中的中间元素设置成根节点,然后将左边的设置为左子树,右边的设置为右子树,然后对左子树和右子树再进行相同的处理(运用递归)。
下面是代码:
struct TreeNode* Traval(int* nums, int left, int right) {
if (left > right)
return NULL;
int mid = (left + right) / 2;
struct TreeNode* root = (struct TreeNode*)malloc(sizeof(struct TreeNode));
root->val = nums[mid];
root->left = Traval(nums, left, mid - 1);
root->right = Traval(nums, mid + 1, right);
return root;
}
struct TreeNode* sortedArrayToBST(int* nums, int numsSize) {
return Traval(nums, 0, numsSize - 1);
}
这里要说的是上面的终止条件(left>right),这里是因为我们传参是left和mid-1或者mid+1和right,如果left>right就证明节点为空,直接返回空节点就可以了。
450. 删除二叉搜索树中的节点
题目
代码
struct TreeNode* deleteNode(struct TreeNode* root, int key){
if(root==NULL)
return NULL;
if(root->val==key){
if(root->left==NULL&&root->right==NULL)
return NULL;
else if(root->left==NULL&&root->right!=NULL)
return root->right;
else if(root->left!=NULL&&root->right==NULL)
return root->left;
else if(root->left!=NULL&&root->right!=NULL){
struct TreeNode* cur=root->right;
while(cur->left!=NULL)
cur=cur->left;
cur->left=root->left;
return root->right;
}
}
if(root->val>key)
root->left=deleteNode(root->left,key);
if(root->val<key)
root->right=deleteNode(root->right,key);
return root;
}
题解
本题我们在删除的地方有五种情况:
- 第一种情况:没找到删除的节点,遍历到空节点直接返回了
- 找到删除的节点
- 第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
- 第三种情况:删除节点的左孩子为空,右孩子不为空,删除节点,右孩子补位,返回右孩子为根节点
- 第四种情况:删除节点的右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
- 第五种情况:左右孩子节点都不为空,则将删除节点的左子树头结点(左孩子)放到删除节点的右子树的最左面节点的左孩子上,返回删除节点右孩子为新的根节点。
如果我们搞清楚了这五种情况,我们运用递归很容易就可以实现这道题。
已经到底啦!!