一、 二叉搜索树的最近公共祖先
力扣第235题
递归三步走:
1. 确定返回值和参数
返回的是目标结点,参数是当前结点以及p,q结点,直接用题目给的函数做递归
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q)
2. 确定终止条件
遍历到空结点直接返回
if(root == null) return null;
3. 单层递归的逻辑
当前结点的值和p,q 值的大小有三种关系
第一种:root.val > p.val && root.val > q.val (当前节点的值大于p,q结点的值)
说明p,q结点的最近公共祖先在当前结点的左子树上;
第二种:root.val < p.val && root.val < q.val (当前节点的值小于p,q结点的值)
说明p,q结点的最近公共祖先在当前结点的右子树上;
第三种:当前结点的值介于p,q两者之间
说明当前节点就是p,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;
整体代码如下:
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) {
return lowestCommonAncestor(root.left, p, q);
}
if(root.val < p.val && root.val < q.val) {
return lowestCommonAncestor(root.right, p, q);
}
return root;
}
}
二、二叉搜索树中的插入操作
力扣第701题
递归三步走:
1. 确定返回值和参数
返回的是目标结点,参数是当前结点以及 p,val 值,直接用题目给的函数做递归
public TreeNode insertIntoBST(TreeNode root, int val)
2. 确定终止条件
当访问到空结点时,说明找到了 val 应该存在的位置,返回val结点
if(root == null) return new TreeNode(val);
3. 单层逻辑处理
当前结点值和目标值 val 的大小有两种关系
第一种:若当前节点值大于 val ,说明val应该出现在当前节点的左子树上,递归左子树,并用左节点接收递归结果(为什么接收?接受的是终止条件!)
第二种:若当前节点值小于 val ,说明val应该出现在当前节点的右子树上,递归右子树,并用右节点接收递归结果
最后,返回当前节点。
if(root.val > val) {
root.left = insertIntoBST(root.left, val);
}
if(root.val < val) {
root.right = insertIntoBST(root.right, val);
}
return root;
(递归)完整代码如下:
class Solution {
public TreeNode insertIntoBST(TreeNode root, int val) {
if(root == null) return new TreeNode(val);
if(root.val > val) {
root.left = insertIntoBST(root.left, val);
}
if(root.val < val) {
root.right = insertIntoBST(root.right, val);
}
return root;
}
}
三、删除二叉搜索树中的节点
力扣第450题:
递归三步走:
1. 确定返回值和参数
public TreeNode deleteNode(TreeNode root, int key)
2. 确定终止条件
当访问到空结点时,说明访问到边界了,返回空值
if(root == null) return null;
3. 单层处理逻辑
当找到目标结点时,总共有以下几种情况
第一种:目标结点为叶子结点,直接返回空值,将其删除
第二种:目标结点左孩子为空,右孩子不为空,返回右孩子,即目标结点被删除,右孩子补位
第三种:目标结点右孩子为空,左孩子不为空,返回左孩子,即目标结点被删除,左孩子补位
第四种:目标节点左右孩子都在,将目标结点左孩子插入到目标结点右孩子的最左边结点的左孩子处,返回目标结点的右孩子
最后:根据当前结点和key的关系进行递归调用,然后返回当前节点
注意:若调用左子树,则用当前结点的左结点指针去接受递归结果,右子树同理
if(root.val == key) {
//第一种情况
if(root.left == null && root.right == null) {
return null;
}
//第二种情况
if(root.left == null) {
return root.right;
}
//第三种情况
if(root.right == null) {
return root.left;
}
//第四种情况
TreeNode node = root.right;
while(node.left != null) {
node = node.left;
}
node.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;
(递归)完整代码如下:
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;
}
//第二种情况
if(root.left == null) {
return root.right;
}
//第三种情况
if(root.right == null) {
return root.left;
}
//第四种情况
TreeNode node = root.right;
while(node.left != null) {
node = node.left;
}
node.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;
}
}