#Java #二叉树
Feeling and experiences:
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。
思路:
? 初始化一个指针?node,从根节点?root?开始。
? 使用循环,当?p?和?q?都小于?node.val?时,说明它们都在?node?的左子树上,因此将?node?更新为?node.left。
? 如果?p?和?q?都大于?node.val,说明它们都在?node?的右子树上,因此将?node?更新为?node.right。
? 如果以上两种情况都不成立,说明当前?node?是?p?和?q?的最近公共祖先,跳出循环。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
TreeNode node = root;
while(true){
if(p.val < node.val && q.val < node.val){
node = node.left;
}else if(p.val > node.val && q.val > node.val){
node = node.right;
}
else{
break;
}
}
return node;
}
}
?
给定二叉搜索树(BST)的根节点?root
?和要插入树中的值?value
?,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 ,新值和原始二叉搜索树中的任意节点值都不同。
注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回 任意有效的结果 。
1. 基本原则:
在二叉搜索树中插入一个新值时,需要保持二叉搜索树的性质。即对于任何节点,其左子树中所有节点的值都比它小,右子树中所有节点的值都比它大。
2. 递归插入:
? 递归基准情况:如果当前节点为?null(表示到达了应该插入新节点的位置),创建一个新的?TreeNode,其值为?val,然后返回这个新节点。
? 递归搜索:
? 如果?val?小于当前节点的值,表示应该在当前节点的左子树中继续寻找插入位置。对当前节点的左子树?(root.left)?调用?insertIntoBST?方法。
? 如果?val?大于当前节点的值,表示应该在当前节点的右子树中继续寻找插入位置。对当前节点的右子树?(root.right)?调用?insertIntoBST?方法。
3. 更新子树链接:在每一层递归中,根据返回的新树的根节点更新当前节点的左或右子节点链接。
4. 返回结果:最终,递归的根调用将返回更新后的树的根节点。
代码如下:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public TreeNode insertIntoBST(TreeNode root, int val) {
if(root == null){
return new TreeNode(val);
}
if(val < root.val){
root.left = insertIntoBST(root.left,val);
}else if(val > root.val){
root.right = insertIntoBST(root.right , val);
}
return root;
}
}
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的?key?对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
一般来说,删除节点可分为两个步骤:
关键点:删除了该节点后,要对二叉搜索树进行维护,保持其性质。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
if (root == null) return null;
// 查找要删除的节点
if (key < root.val) {
root.left = deleteNode(root.left, key);
} else if (key > root.val) {
root.right = deleteNode(root.right, key);
} else {
// 找到了要删除的节点
// 情况1: 只有一个子节点或没有子节点
if (root.left == null) {
return root.right;
} else if (root.right == null) {
return root.left;
}
// 情况2: 有两个子节点
TreeNode minNode = findMin(root.right);
root.val = minNode.val;
root.right = deleteNode(root.right, root.val);
}
return root;
}
private TreeNode findMin(TreeNode node) {
while (node.left != null) {
node = node.left;
}
return node;
}
}
整体思路如下:
1. 查找要删除的节点:
? 如果要删除的节点值小于当前节点的值,向左子树递归。
? 如果要删除的节点值大于当前节点的值,向右子树递归。
? 如果要删除的节点值等于当前节点的值,那么这个节点就是我们要删除的节点。
2. 删除节点:一旦找到要删除的节点,有三种情况:
? 叶子节点(没有子节点):直接删除该节点,返回?null。
? 只有一个子节点:删除该节点,并返回其唯一的子节点作为新的子树的根。
? 有两个子节点:需要找到要删除节点的右子树中的最小节点(或左子树中的最大节点),这个节点将替换要删除的节点。然后递归地删除那个最小(或最大)节点。
3. 维持BST的性质:在删除节点后,需要通过调整树的结构来保持二叉搜索树的性质。
云青青兮欲雨,
水澹澹兮生烟~
Fighting!
?
?
?
?
?