代码随想录算法训练营第17天|235. 二叉搜索树的最近公共祖先、701. 二叉搜索树中的插入操作、450. 删除二叉搜索树中的节点
LeetCode235
2025-02-16 16:47:00 星期日
题目描述:力扣235
文档讲解:代码随想录(programmercarl)235. 二叉搜索树的最近公共祖先
视频讲解:《代码随想录》算法视频公开课:二叉搜索树找祖先就有点不一样了!| 235. 二叉搜索树的最近公共祖先
代码随想录视频内容简记
这道题目因为是一棵二叉搜索树,所以有显示的遍历顺序可以直接用,所以本题的遍历顺序就不重要了,说不重要就是因为没有中间结点的处理
递归法
梳理
-
if (cur == NULL) return NULL;终止条件 -
确定单层递归的逻辑
-
首先是向左,
if (cur->val > p && cur->val > q) left = traversal(cur->left, p, q),这里注意,后面还有一句if (left != NULL) return left,其实一开始不太明白这句的作用是什么,但是一想,如果left = traversal()了以后,就必须要进行一个返回,来让下一步的递归继续,要不然中间所有的递归就断开了 -
然后是向右,一模一样
-
最后剩余的情况就是应该直接返回
-
迭代法
梳理
-
while (cur != NULL)向下进行遍历, -
向左遍历,
if (cur->val > p->val && cur->val > q->val) cur = cur->left -
向右同理,
else if (cur->val < p->val && cur->val < q->val) cur = cur->right -
最后返回
return cur
LeetCode测试
递归法
点击查看代码
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if (root == NULL) return NULL;
if (root->val > p->val && root->val > q->val) {
TreeNode* left = lowestCommonAncestor(root->left, p, q);
if (left != NULL) return left;
}
if (root->val < p->val && root->val < q->val) {
TreeNode* right = lowestCommonAncestor(root->right, p, q);
if (right != NULL) return right;
}
return root;
}
};
迭代法
点击查看代码
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
while (root != NULL) {
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 NULL;
}
};
LeetCode701
题目描述:力扣701
文档讲解:代码随想录(programmercarl)701. 二叉搜索树中的插入操作
视频讲解:《代码随想录》算法视频公开课:原来这么简单? | LeetCode:701.二叉搜索树中的插入操作
代码随想录视频内容简记
在一棵二叉搜索树中插入一个新的结点,其总会变成叶子结点
梳理
-
if (cur == NULL),此处的终止条件反而要进行插入操作,TreeNode* root = new TreeNode(val),开辟一个新的结点,之后return -
向左遍历,
if (val < cur->val) root->left = traversal(root->left) -
之后向右遍历同理。
但是这里有个疑问,就是上面的root->left = traversal(root->left),一些成下面这样子就都不对了,虽然感觉逻辑上是一致的,但是我估计一是,这样写是root是接不住后面递归的子树的,二是重新定义TreeNode* left也会有问题,所以不对。
if (val < root->val) {
TreeNode* left = insertIntoBST(root->left, val);
return left;
}
LeetCode测试
正确的代码如下,不长
点击查看代码
class Solution {
public:
TreeNode* insertIntoBST(TreeNode* root, int val) {
if (root == NULL) {
TreeNode* cur = new TreeNode(val);
return cur;
}
// 确定单层递归的逻辑
if (val < root->val) root->left = insertIntoBST(root->left, val);
if (val > root->val) root->right = insertIntoBST(root->right, val);
return root;
}
};
LeetCode450
题目描述:力扣450
文档讲解:代码随想录(programmercarl)450. 删除二叉搜索树中的节点
视频讲解:《代码随想录》算法视频公开课:调整二叉树的结构最难!| LeetCode:450.删除二叉搜索树中的节点
代码随想录视频内容简记
按照递归三部曲来分析,这道题复杂的地方在于确定递归的终止条件,这里比较复杂。另外感觉本题的遍历顺序也不那么重要,没有对中间结点的处理过程
梳理
-
确定函数的返回值和参数
-
确定递归的终止条件
-
找不到要删除的结点
-
要删除结点为叶子结点
-
要删除的结点,左为空,右不为空
-
要删除的结点,左不为空,右为空
-
要删除的结点,左右都不为空
-
-
确定单层递归的逻辑
大致代码内容
- 确定递归的终止条件,
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 {
.....
}
}
当出现左不为空,右也不为空的时候,这里默认把右子树继位,其实左子树也一样,因为这不是一棵平衡二叉树,所以都行。既然选定了右子树,那么找到右子树的最左下结点,就可以把root的左子树安排为最左下结点的左子树
else {
TreeNode* cur = root->right;
while (cur->left != NULL) {
cur = cur->left;
}
// 这里把root左子树安排到位
cur->left = root->left;
// 这里就变成了左为空,右不为空的情况,直接返回root的右子树
return root->right;
}
-
确定单层递归的逻辑,
向左,
if (key < root->val) root->left = deleteNode(root->left, key);向右,
if (key > root->val) root->right = deleteNode(root->right, key);
LeetCode测试
注意有一些小细节
-
在定义了cur指针之后,while的循环条件一开始写的
while (cur != NULL)这样出现的问题是就是出现了对控制真的操作,所以正确的应该是while (cur->left != NULL) -
最后单层递归的逻辑,一开始写的是
root = deleteNode(root->left, key),这样root的左孩子就接不住了,写成root->left = deleteNode(root->left, key)才对,姑且这样理解
点击查看代码
class Solution {
public:
TreeNode* deleteNode(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 {
TreeNode* cur = root->right;
while (cur->left != NULL) {
cur = cur->left;
}
// 这里把root左子树安排到位
cur->left = root->left;
// 这里就变成了左为空,右不为空的情况,直接返回root的右子树
return root->right;
}
}
if (key < root->val) root->left = deleteNode(root->left, key);
if (key > root->val) root->right = deleteNode(root->right, key);
return root;
}
};
浙公网安备 33010602011771号