代码随想录day19|235二叉搜索树最近公共祖先701二叉搜索树插入450二叉搜索树删除|01笔记

101 阅读2分钟
  • 235二叉搜索树最近公共祖先

  • 代码随想录 (programmercarl.com)
  • 第一印象

  • 当做普通二叉树的方法是利用后序遍历的回溯机制,返回目标结点。当左右子树返回值都非空时,即为公共祖先,然后递归返回即可。
  • 讲解观后感

  • 本题利用二叉搜索树的特性主要有两个方便的地方。一是公共祖先一定是在两目标点取值范围内;另一个是最近公共祖先是向下搜索中第一个满足这样取值范围的点。
  • 解题代码

  • 迭代法
  •     /**
         * Definition for a binary tree node.
         * type TreeNode struct {
         *     Val   int
         *     Left  *TreeNode
         *     Right *TreeNode
         * }
         */
        
        func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
            for root!=nil {
                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 {
                    return root
                }
            }
            return root 
        }
        
    
  • 递归:
  •     func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
            if (root.Val - p.Val) * (root.Val - q.Val) <= 0 {
                return root 
            } 
            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
        }
    
  • 701二叉搜索树中的插入操作

  • 代码随想录 (programmercarl.com)
  • 第一印象

  • 因为任意插入的方式均可。可以从根节点开始,存储当前结点root与其父结点pre,根据大小关系向下迭代查找。得到最后一个pre后,根据大小关系进行连接。
  • 讲解观后感

  • 递归的方式是直接利用指针承接向下查找,遇到空节点之后插入再回到根节点返回值。
  • 解题代码

  • 迭代
  •     
        func insertIntoBST(root *TreeNode, val int) *TreeNode {
            
            newNode := &TreeNode{Val:val}
            if root==nil {
                return newNode
            }
            pre := root
            cur := root
            for cur!=nil {
                if cur.Val>val {
                    pre = cur
                    cur = cur.Left
                } else if cur.Val<val {
                    pre = cur
                    cur = cur.Right
                } else {
                    break
                }
            }
            if pre!=nil && pre.Val > val {
                pre.Left = newNode
            } 
            if pre!=nil && pre.Val < val {
                pre.Right = newNode
            }
            
            return root
        }
    
  • 递归
  •     func insertIntoBST(root *TreeNode, val int) *TreeNode {
            if root == nil {
                root = &TreeNode{Val: val}
                return root
            }
            if root.Val > val {
                root.Left = insertIntoBST(root.Left, val)
            } else {
                root.Right = insertIntoBST(root.Right, val)
            }
            return root
        }
    
  • 450删除二叉搜索树中的节点

  • 代码随想录 (programmercarl.com)
  • 第一印象

  • 删除节点后为了保证搜索二叉树的性质,要做很多调整的讨论,具体情况还是在代码中看比较清晰。
  • 讲解观后感

  • 把二叉搜索树中删除节点遇到的情况总结如下。五种情况:
  • 第一种情况:没找到删除的节点,遍历到空节点直接返回了
  • 找到删除的节点
  • 第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
  • 第三种情况:删除节点的左孩子为空,右孩子不为空,删除节点,右孩子补位,返回右孩子为根节点
  • 第四种情况:删除节点的右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
  • 第五种情况:左右孩子节点都不为空,则将删除节点的左子树头结点(左孩子)放到删除节点的右子树的最左面节点的左孩子上,返回删除节点右孩子为新的根节点。
  • 二叉树固用删除方法

  • 代码中目标节点(要删除的节点)被操作了两次:
    • 第一次是和目标节点的右子树最左面节点交换。
    • 第二次直接被NULL覆盖了。
  • 解题代码

  • 递归
  •     
        func deleteNode(root *TreeNode, key int) *TreeNode {
            if root==nil {
                return nil
            }
            if root.Val==key {
                if root.Left==nil&&root.Right==nil {
                    return nil
                }
                if root.Left==nil || root.Right==nil {
                    if root.Left==nil {
                        return root.Right
                    } else {
                        return root.Left
                    }
                }
                if root.Left!=nil&&root.Right!=nil {
                    node := root.Left
                    right := root.Right
                    for right.Left!=nil {
                        right = right.Left
                    }
                    right.Left = node
                    return root.Right
                }
            } else if root.Val < key {
                root.Right = deleteNode(root.Right, key)
            } else {
                root.Left = deleteNode(root.Left, key)
            }
            return root
             
        }
    
  • 迭代
  •     // 迭代版本
        func deleteOneNode(target *TreeNode) *TreeNode {
        	if target == nil {
        		return target
        	}
        	if target.Right == nil {
        		return target.Left
        	}
        	cur := target.Right
        	for cur.Left != nil {
        		cur = cur.Left
        	}
        	cur.Left = target.Left
        	return target.Right
        }
        func deleteNode(root *TreeNode, key int) *TreeNode {
        	// 特殊情况处理
        	if root == nil {
        		return root
        	}
        	cur := root
        	var pre *TreeNode
        	for cur != nil {
        		if cur.Val == key {
        			break
        		}
        		pre = cur
        		if cur.Val > key {
        			cur = cur.Left
        		} else {
        			cur = cur.Right
        		}
        	}
        	if pre == nil {
        		return deleteOneNode(cur)
        	}
        	// pre 要知道是删除左孩子还有右孩子
        	if pre.Left != nil && pre.Left.Val == key {
        		pre.Left = deleteOneNode(cur)
        	}
        	if pre.Right != nil && pre.Right.Val == key {
        		pre.Right = deleteOneNode(cur)
        	}
        	return root
        }