第六章 二叉树part07
235. 二叉搜索树的最近公共祖先
相对于 二叉树的最近公共祖先 本题就简单一些了,因为 可以利用二叉搜索树的特性。
题目链接/文章讲解:https://programmercarl.com/0235.%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91%E7%9A%84%E6%9C%80%E8%BF%91%E5%85%AC%E5%85%B1%E7%A5%96%E5%85%88.html
视频讲解:https://www.bilibili.com/video/BV1Zt4y1F7ww
701.二叉搜索树中的插入操作
本题比想象中的简单,大家可以先自己想一想应该怎么做,然后看视频讲解,就发现 本题为什么比较简单了。
题目链接/文章讲解:https://programmercarl.com/0701.%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91%E4%B8%AD%E7%9A%84%E6%8F%92%E5%85%A5%E6%93%8D%E4%BD%9C.html
视频讲解:https://www.bilibili.com/video/BV1Et4y1c78Y
450.删除二叉搜索树中的节点
相对于 插入操作,本题就有难度了,涉及到改树的结构
题目链接/文章讲解:https://programmercarl.com/0450.%E5%88%A0%E9%99%A4%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91%E4%B8%AD%E7%9A%84%E8%8A%82%E7%82%B9.html
视频讲解:https://www.bilibili.com/video/BV1tP41177us
235. 二叉搜索树的最近公共祖先
题目链接
https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-search-tree/description/
解题思路
1.因为是有序树,所以 如果 中间节点是 q 和 p 的公共祖先,那么 中节点的数组 一定是在 [p, q]区间的
2.只要从上到下去遍历,遇到 cur节点是数值在[p, q]区间中则一定可以说明该节点cur就是p 和 q的公共祖先。 那问题来了,一定是最近公共祖先吗?
证明一下:
因为是二叉搜索树,中间节点在[p, q]区间,如果遇到了第一个节点在这个区间:
2.1 向左都是小于这个节点的,所以左子树不可能存在q
2.2 向右都是大于这个节点的,所在右子树不可能存在p
所以遇到的第一个节点一定是p和q的最近公共祖先。
3.递归遍历顺序,本题就不涉及到 前中后序了(这里没有中节点的处理逻辑,遍历顺序无所谓了)
code
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;
}
}
//此时就说明在p和q之间了
return root;
}
701.二叉搜索树中的插入操作
题目链接
https://leetcode.cn/problems/insert-into-a-binary-search-tree/description/
解题思路
有多种有效的插入方式,还可以重构二叉搜索树,一下子吓退了不少人,可以不用考虑改变树结构的插入方式,那么就简单了,就说明解题的时候审题的重要性,有些可忽略有些不可忽略。
利用返回值完成新加入的节点与其父节点的赋值操作的思想:
通过递归函数返回值完成了新加入节点的父子关系赋值操作,下一层将节点返回,本层用root.left或root.right 接住
解题流程:
只要按照二叉搜索树的规则去遍历,遇到空节点就插入节点就可以了
根据二叉搜索树的特性,去判断它是向左递归还是向右
val<root.val 去左子树
val>root.val 去右子树
直到找到一个null值,说明找到了它的位置,这个null值的空节点就是这个val新节点,返回给递归函数赋值给腹父节点。
code
public TreeNode insertIntoBST(TreeNode root, int val) {
if(root==null){
return new TreeNode(val);
}
if(val < root.val){
root.left=insertIntoBST(root.left,val);
}
if(val > root.val){
root.right=insertIntoBST(root.right,val);
}
return root;
}
450. 删除二叉搜索树中的节点
题目链接
https://leetcode.cn/problems/delete-node-in-a-bst/description/
解题思路
删除节点的操作是通过返回值来操作,通过递归返回值来把新节点赋值给父节点。
root==null 是终止条件 找到要删的点也是终止条件,找到删的点后要处理逻辑,最终返回新的节点给父节点。
分析下面几种情况,可以画图模拟下
分治递归,像是前序遍历
分治递归的核心思想是将一个问题分解为多个子问题分别求解,然后将子问题的解组合起来得到原问题的解
在前中后序这些遍历方法中,都遵循分治递归的思想:
分解问题:对每个节点,都将其左子树和右子树视为子问题。
解决子问题:通过递归调用,在子树上继续执行相同的遍历操作。
合并结果:根据遍历的顺序,将子树的遍历结果组合起来。
前序、中序和后序遍历都可以视为分治递归的具体应用。
code
public TreeNode deleteNode(TreeNode root, int key) {
//1.没找到要删除的节点 返回null
if(root==null){
return null;
}
//找到要删除的节点
if(root.val==key){
//2.左右都未null 不需要额外处理直接返回null就是删除当前的节点
if(root.left==null&&root.right==null){
return null;
//3.左右都不为null 把左节点放入到右节点的最左节点,分析搜索树的特性即可
}else if(root.left!=null&&root.right!=null){
TreeNode cur=root.right;
while(cur.left!=null){
cur=cur.left;
}
cur.left=root.left;
return root.right;
//4.左不为null右为null 返回节点即可
}else if(root.left!=null){
return root.left;
//5.右不为null 左为null 返回节点即可
}else if(root.right!=null){
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;
}
扩展 根据数组构建二叉树
public class BinaryTreeBuilder {
// 根据数组构建二叉树
public static TreeNode buildTree(Integer[] nodes) {
if (nodes == null || nodes.length == 0) {
return null;
}
Queue<TreeNode> queue = new LinkedList<>();
TreeNode root = new TreeNode(nodes[0]);
queue.add(root);
int i = 1;
while (!queue.isEmpty() && i < nodes.length) {
TreeNode current = queue.poll();
if (i < nodes.length && nodes[i] != null) {
current.left = new TreeNode(nodes[i]);
queue.add(current.left);
}
i++;
if (i < nodes.length && nodes[i] != null) {
current.right = new TreeNode(nodes[i]);
queue.add(current.right);
}
i++;
}
return root;
}
}
public static void main(String[] args) {
TreeNode treeNode = BinaryTreeBuilder.buildTree(new Integer[]{3,2,5,null,null,4,10,null,null,8,15,7});
new Solution().deleteNode(treeNode, 5);
}