235.二叉搜索树的最近公共祖先

文章:28. 二叉搜索树的最近公共祖先

题目:235. 二叉搜索树的最近公共祖先

【思路】

二叉搜索树:找到一个节点的值在两边的子树、在p和q之间(一定是最近的公共祖先!)

  • Java实现

会出现乘积溢出的情况:

1
2
3
if((root.val - p.val) * (root.val - q.val) <= 0){
return root;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
while(true){
if(root.val >p.val && root.val > q.val){
return lowestCommonAncestor(root.left,p,q);
}
else if(root.val < p.val && root.val <q.val){
return lowestCommonAncestor(root.right,p,q);
}else{
break;
}

}
return root;
}
}
  • Go实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
if root == nil {
return root
}
for{
if root.Val > p.Val && root.Val > q.Val{
root = root.Left
}
if root.Val <p.Val && root.Val <q.Val{
root = root.Right
}
//保证数值为一正一负,则说明数值在当前节点的左右子树!
if (root.Val - p.Val) * (root.Val - q.Val) <=0{
return root
}
}
return root
}

701.二叉搜索树中的插入操作

文章:29. 二叉搜索树中的插入操作

题目:701. 二叉搜索树中的插入操作

【思路】

在不调整二叉树的结构的前提下,找到空节点插入元素即可。因此我们需要对二叉搜索树进行遍历操作(递归)。

递归三部曲

  • 确定递归函数参数以及返回值

    • 有返回值的话会方便我们用节点来接住递归返回的值。
  • 确定终止条件

  • 确定单层递归的逻辑

    • 需要明确不需要搜索整棵树,因为本树是二叉搜索树!
  • Java实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution {
public TreeNode insertIntoBST(TreeNode root, int val) {
if(root == null){
TreeNode node = new TreeNode(val);
return node;
}
if(root.val > val){
root.left = insertIntoBST(root.left,val);
}
if(root.val < val){
root.right = insertIntoBST(root.right,val);
}
return root;
}
}
  • Go实现
1
2
3
4
5
6
7
8
9
10
11
12
13
func insertIntoBST(root *TreeNode, val int) *TreeNode {
if root == nil{
node := &TreeNode{Val: val}
return node
}
if root.Val > val{
root.Left = insertIntoBST(root.Left,val)
}
if root.Val < val{
root.Right = insertIntoBST(root.Right,val)
}
return root
}

450.删除二叉搜索树中的节点

文章:30. 删除二叉搜索树中的节点

题目:调整二叉树的结构最难!| LeetCode:450.删除二叉搜索树中的节点_哔哩哔哩_bilibili

【思路】

不可避免的需要去调整二叉树的结构。

第一种情况:没找到要删除的节点

第二种情况:要删除的节点是叶子节点

第三种情况:要删除的节点左子树不空,右子树空\左子树空,右子树不空

第四种情况:要删除的节点左不为空右不为空

回溯:解决单层处理逻辑

  • Java实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
return traversal(root,key);
}
public TreeNode traversal(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.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;
}
}
if(key < root.val) root.left = traversal(root.left,key);
if(key > root.val) root.right = traversal(root.right,key);
return root;
}
}
  • Go实现

忘记写单层遍历的逻辑了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
func deleteNode(root *TreeNode, key int) *TreeNode {
return traversal(root,key)
}
func traversal(root *TreeNode,key int)*TreeNode{
if root == nil{
return nil
}
if root.Val == key{
if root.Left == nil && root.Right == nil{
return nil
}else if root.Left != nil && root.Right == nil{
return root.Left
}else if root.Left == nil && root.Right != nil{
return root.Right
}else{
cur := root.Right
for cur.Left != nil{
cur = cur.Left
}
cur.Left = root.Left
return root.Right
}
}
//单层遍历逻辑
root.Left = traversal(root.Left , key)
root.Right = traversal(root.Right,key)
return root
}

【算法总结】

  • 二叉搜索树的公共祖先:使用递归,保证数值为一正一负,则说明数值在当前节点的左右子树!(但是存在数值溢出的风险)我们可以选择break直接返回(条件要严苛一点)。
  • 二叉搜索树中的插入操作:使用递归,二叉搜索树的特性使我们直接在空节点处插入数值即可,不涉及对树结构的修改。
  • 删除二叉搜索树中的节点:使用递归,需要注意区分三种情况。第四种改变结构的情况需要注意,新建一个node节点来操作二叉树与key相等的节点的right节点,将与key相等的节点包含的树都加入进right节点的左节点的left节点(左节点要为空),重新构建好该节点后返回root.right节点(与key相等的节点需要删除)。