系列文章目录
目录
- 系列文章目录
- 235. 二叉搜索树的最近公共祖先
- ①递归法
- 自己写的
- 简洁版
- ②迭代法
- 不能这样写!
- 正确写法
- 701.二叉搜索树中的插入操作
- ①递归法
- ②迭代法
- 450.删除二叉搜索树中的节点
- 递归法
235. 二叉搜索树的最近公共祖先
①递归法
自己写的
class Solution {TreeNode result;public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {//终止条件if (root == null || root == p || root == q) return root;if (root.val > p.val && root.val > q.val) {result = lowestCommonAncestor(root.left,p,q);} else if (root.val < p.val && root.val < q.val) {result = lowestCommonAncestor(root.right,p,q);} else {return root;}return result;}
}
简洁版
class Solution {public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode 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;}
}
②迭代法
不能这样写!
图片来自热心网友(大佬)
5
和6
的最近公共祖先是8
而不是4
。
class Solution {public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {while (root.val > p.val && root.val > q.val) root = root.left;while (root.val < p.val && root.val < q.val) root = root.right;return root;}
}
正确写法
class Solution {public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {while (true) {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;}
}
701.二叉搜索树中的插入操作
①递归法
递归三部曲:
- 确定递归函数参数以及返回值:参数就是根节点指针,以及要插入元素,这里递归函数要不要有返回值呢?可以有,也可以没有,但递归函数如果没有返回值的话,实现是比较麻烦的,下面也会给出其具体实现代码。有返回值的话,可以利用返回值完成新加入的节点与其父节点的赋值操作。
- 确定终止条件:终止条件就是找到遍历的节点为
null
的时候,就是要插入节点的位置了,并把插入的节点返回。 - 确定单层递归的逻辑:
- 如果
root.val > val
,说明应该将val
插入左子树- 如果左子树不存在,将
val
作为root.left
- 如果左子树存在,让左子树插入
val
- 如果左子树不存在,将
- 如果
root.val < val
,说明应该将val
插在右子树- 如果右子树不存在,将
val
作为root.right
- 如果右子树存在,让右子树插入
val
- 如果右子树不存在,将
- 返回插入
val
后的根节点,即左右子树插入节点后的根节点。
- 如果
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);} else if (root.val < val) {root.right=insertIntoBST(root.right, val);}return root;}
}
②迭代法
迭代法遍历的过程中,需要记录一下当前遍历的节点的父节点,这样才能做插入节点的操作。用pre
指针来记录上一个节点。
class Solution {public TreeNode insertIntoBST(TreeNode root, int val) {if (root == null) return new TreeNode(val); // root为空,直接插入后返回TreeNode newRoot = root;//记录根节点TreeNode pre = null;// 这个很重要,需要记录上一个节点,否则无法赋值新节点while (root != null) {pre = root;if (root.val > val) {root = root.left;} else if (root.val < val) {root = root.right;}}//插入节点的操作if (pre.val > val) {pre.left = new TreeNode(val);} else {pre.right = new TreeNode(val);}return newRoot;}
}
450.删除二叉搜索树中的节点
二叉搜素树的性质:
左子树的所有val
值 <
当前节点的val
值 <
右子树的最小val
值 =
右子树的最左边节点的val
值。
递归法
递归三部曲:
- 确定递归函数参数以及返回值:通过递归返回值删除节点。
- 确定终止条件:删除当前节点的逻辑放在终止条件中,二叉搜索树中删除节点有以下五种情况:
- 第一种情况:没找到删除的节点,遍历到空节点直接返回了;
- 找到删除的节点
- 第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点;
- 第三种情况:删除节点的左孩子为空,右孩子不为空,删除节点,右孩子补位,返回右孩子为根节点的右子树;
- 第四种情况:删除节点的右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点的左子树;
- 第五种情况:左右孩子节点都不为空,则将删除节点的左子树头结点(左孩子)放到删除节点的右子树的最左面节点的左孩子上,返回删除节点的右节点,作为删除后树的根节点。
注
:终止条件可以简化为:
if (root == null) return root;//找不到要删除的节点,返回nullif (root.val == key) {if (root.left == null) {return root.left;} else if (root.right == null) {return root.right;} else {TreeNode cur = root.right;while (cur.left != null) {cur = cur.left;}cur.left = root.left;return root.right;}}
其中当要删除的节点的左右子树都不为空,一直循环找到右子树最左边的节点时,注意判断条件必须为while (cur.left != null)
而不能是while (cur != null)
,否则会在cur.left = root.left;
这里报空指针异常。
class Solution {public TreeNode deleteNode(TreeNode root, int key) {//终止条件if (root == null) return root;//找不到要删除的节点,返回nullif (root.val == key) {if (root.left == null && root.right == null) {//若为叶子节点return null;} else if (root.left != null && root.right == null) {//若左不为空右为空,返回左子树return root.left;} else if (root.left == null && root.right != null) {//若右不为空左为空,返回右子树return root.right;} else {//左右子树都不为空TreeNode cur = root.right;while (cur.left != null) {//一直循环找到右子树最左边的节点cur = cur.left;}cur.left = root.left;//将要删除的节点的左子树拼接到右子树最左边的节点return root.right;//返回要删除的节点右子树}}// 如果root.val > key,证明要删除的节点应该会出现在左子树上,获取左子树删除key节点后的根节点作为新的左节点if (root.val > key) root.left = deleteNode(root.left, key);// 如果root.val < key,证明要删除的节点应该会出现在右子树上,获取右子树删除key节点后的根节点作为新的右节点if (root.val < key) root.right = deleteNode(root.right, key);// 返回删除key节点后的根节点return root;}
}