给定二叉搜索树(BST)的根节点 root
和要插入树中的值 value
,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 ,新值和原始二叉搜索树中的任意节点值都不同。
注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回 任意有效的结果 。
示例 1:
输入:root = [4,2,7,1,3], val = 5 输出:[4,2,7,1,3,5] 解释:另一个满足题目要求可以通过的树是:
示例 2:
输入:root = [40,20,60,10,30,50,70], val = 25 输出:[40,20,60,10,30,50,70,null,null,25]
示例 3:
输入:root = [4,2,7,1,3,null,null,null,null,null,null], val = 5 输出:[4,2,7,1,3,5]
提示:
[0, 104]
的范围内。-108 <= Node.val <= 108
Node.val
是 独一无二 的。-108 <= val <= 108
val
在原始BST中不存在。利用递归。
如果当前节点为空,则不存在最近公共祖先,返回null.
如果当前节点的值同时大于pq的值,说明pq节点在当前节点的左边,向左递归继续寻找最近公共祖先,如果找到了就把最近公共祖先返回。
同理如果当前节点的值同时小于pq的值,说明pq节点都在当前节点的右边,向右递归继续寻找最近公共祖先,找到了,就把最近公共祖先返回。
如果当前节点的左右子树都没有找到最近公共祖先,说明当前节点就是pq的公共祖先,返回当前节点。
代码如下:
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null) return null;//如果当前节点为空,返回null
if(root.val > p.val && root.val > q.val) {//如果当前节点的值同时大于pq的值,说明pq节点在当前节点的左子树
TreeNode left = lowestCommonAncestor(root.left, p, q);//向左子树递归寻找最近公共祖先
if(left != null) return left;//如果找到了就返回最近公共祖先
}
if(root.val < p.val && root.val < q.val) {//如果当前节点值同时小于pq,说明pq节点在当前节点的右子树
TreeNode right = lowestCommonAncestor(root.right,p , q);//向右子树递归寻找最近公共祖先
if(right != null) return right;//如果找到了就返回
}
return root;//如果左右子树都没有最近公共祖先,说明当前节点就是最近公共祖先,返回当前节点
}
}
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]
示例 1:
输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8 输出: 6 解释: 节点2
和节点8
的最近公共祖先是6。
示例 2:
输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4 输出: 2 解释: 节点2
和节点4
的最近公共祖先是2
, 因为根据定义最近公共祖先节点可以为节点本身。
说明:
利用递归。
如果当前节点为空,将val值创建成节点返回。
如果当前节点的值大于val,通过递归将节点创建在当前节点的右子树。
如果当前节点的值小于val,通过递归将节点创建在当前节点的左子树。
代码如下:
class Solution {
public TreeNode insertIntoBST(TreeNode root, int val) {
if(root == null) {//如果当前为空,将val创建成节点后返回
TreeNode node = new TreeNode(val);
return node;
}
if(root.val > val) root.left = insertIntoBST(root.left,val);//如果val小于当前节点的值,通过递归,将val插入到当前节点的左子树。
else if(root.val < val) root.right = insertIntoBST(root.right,val);//如果val大于当前节点的值,通过递归将val插入到右子树
return root;//最后返回当前节点
}
}
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
一般来说,删除节点可分为两个步骤:
示例 1:
输入:root = [5,3,6,2,4,null,7], key = 3 输出:[5,4,6,2,null,null,7] 解释:给定需要删除的节点值是 3,所以我们首先找到 3 这个节点,然后删除它。 一个正确的答案是 [5,4,6,2,null,null,7], 如下图所示。 另一个正确答案是 [5,2,6,null,4,null,7]。
示例 2:
输入: root = [5,3,6,2,4,null,7], key = 0 输出: [5,3,6,2,4,null,7] 解释: 二叉树不包含值为 0 的节点
示例 3:
输入: root = [], key = 0 输出: []
提示:
[0, 104]
.-105 <= Node.val <= 105
root
是合法的二叉搜索树-105 <= key <= 105
进阶: 要求算法时间复杂度为 O(h),h 为树的高度。
如果当前节点为空,说明没有要删除的节点,返回null。
如果当前节点值小于目标值key,说明要删除的节点在当前节点的右子树,向右递归去删除目标节点。
同理如果当前节点的值大于目标值key,说明要删除的节点在当前节点的左子树,向左递归去删除目标节点。
如果当前节点的值等于目标值key,也即当前节点为要删除的节点,那么对该节点进行删除操作:
1、如果当前节点只有右子树,那么返回当前节点的右子节点即可(相当于删除当前节点)
2、如果当前节点只有左子树,那么返回当前节点的左子节点。
3、如果当前节点既有左子树也有右子树,那么将左子树的根节点放到右子树的左下角位置(为了保持删除当前节点后,还具有二叉搜索树的性质,想一想这时为什么)
4、如果当前节点没有左右子树,那么直接返回null。
要注意回溯,每层递归时如果不删除当前节点都要将当前节点返回。
代码如下:
class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
if(root == null) return root;//如果当前节点为空,返回null
if(root.val < key) root.right = deleteNode(root.right, key);//如果当前节点的值小于key说明目标节点可能在当前节点的右子树,向右递归去删除目标节点
else if(root.val > key) root.left = deleteNode(root.left, key);//如果当前节点大于key说明目标节点可能在当前节点的左子树,向左递归去删除目标节点
else {//当前节点的值等于key,即当前节点为目标节点,对当前节点进行删除操作
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) {//如果目标节点有左右子树,将左子树的根节点,放到右子树的左下角(为了保证二叉搜索树性质)。
TreeNode node = root.right;
while(node.left != null) node = node.left;
node.left = root.left;
return root.right;
}else {//如果左右子树都为空,返回null即可
return null;
}
}
return root;//注意回溯,返回当前节点
}
}
对于二叉树的操作,我们要有递归和回溯的思想。