算法训练营 day22 二叉树 二叉搜索树的最近公共祖先 二叉搜索树中的插入操作 删除二叉搜索树中的节点
二叉搜索树的最近公共祖先
235. 二叉搜索树的最近公共祖先 - 力扣(LeetCode)
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
因为是有序树,所有 如果 中间节点是 q 和 p 的公共祖先,那么 中节点的数组 一定是在 [p, q]区间的。即 中节点 > p && 中节点 < q 或者 中节点 > q && 中节点 < p。
递归法
-
确定递归函数返回值以及参数
参数就是当前节点,以及两个结点 p、q。
返回值是要返回最近公共祖先,所以是TreeNode 。
-
确定终止条件
遇到空返回就可以了
-
确定单层递归的逻辑
在遍历二叉搜索树的时候就是寻找区间[p.val, q.val](注意这里是左闭又闭)
那么如果 cur.val 大于 p.val,同时 cur.val 大于q.val,那么就应该向左遍历(说明目标区间在左子树上)。
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) {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) {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. 二叉搜索树中的插入操作 - 力扣(LeetCode)
给定二叉搜索树(BST)的根节点 root 和要插入树中的值 value ,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 ,新值和原始二叉搜索树中的任意节点值都不同。
注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回 任意有效的结果 。
如下演示视频中可以看出:只要按照二叉搜索树的规则去遍历,遇到空节点就插入节点就可以了。
递归法
class Solution {public TreeNode insertIntoBST(TreeNode root, int val) {if (root == null) // 如果当前节点为空,也就意味着val找到了合适的位置,此时创建节点直接返回。return new TreeNode(val);if (root.val < val){root.right = insertIntoBST(root.right, val); // 递归创建右子树}else if (root.val > val){root.left = insertIntoBST(root.left, val); // 递归创建左子树}return root;}
}
迭代法
class Solution {public static TreeNode insertIntoBST(TreeNode root, int val) {if (root == null) return new TreeNode(val);TreeNode result = root;TreeNode pre=null;while (root != null) {pre = root;//保存前一个节点if (root.val < val) root = root.right;else if (root.val > val) root = root.left;}if (root==null){if (pre.val > val) {pre.left = new TreeNode(val);} else {pre.right = new TreeNode(val);}}return result;}
}
删除二叉搜索树中的节点
450. 删除二叉搜索树中的节点 - 力扣(LeetCode)
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
一般来说,删除节点可分为两个步骤:
首先找到需要删除的节点;
如果找到了,删除它。
这里就把二叉搜索树中删除节点遇到的情况都搞清楚。
有以下五种情况:
- 第一种情况:没找到删除的节点,遍历到空节点直接返回了
- 找到删除的节点
- 第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
- 第三种情况:删除节点的左孩子为空,右孩子不为空,删除节点,右孩子补位,返回右孩子为根节点
- 第四种情况:删除节点的右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
- 第五种情况:左右孩子节点都不为空,则将删除节点的左子树头结点(左孩子)放到删除节点的右子树的最左面节点的左孩子上,返回删除节点右孩子为新的根节点。
递归法
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.left;}//第四种情况目标值右为空 左不为空else if (root.right!=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;}}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;TreeNode cur = root;TreeNode pre = null;while (cur != null) {if (cur.val == key) break;pre = cur;if (cur.val > key) cur = cur.left;else if (cur.val < key) cur = cur.right;}if (pre == null) {return deleteOneNode(cur);}if (pre.left != null && pre.left.val == key) {pre.left = deleteOneNode(cur);}if (pre.right != null && pre.right.val == key) {pre.right = deleteOneNode(cur);}return root;}private TreeNode deleteOneNode(TreeNode root) {//第二种情况目标值为叶子节点if (root.left==null&&root.right==null){return null;}//第三种情况目标值左为空 右不为空else if (root.left!=null&&root.right==null){return root.left;}//第四种情况目标值右为空 左不为空else if (root.right!=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;}}
}