代码随想录 day22 第六章 二叉树part08

今日内容:

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

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

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

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

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

  • 思路
    • 当我们从上向下去递归遍历,第一次遇到 cur节点是数值在[q, p]区间中,那么cur就是 q和p的最近公共祖先
      • 此时 q p 一定处于左右孩子中,或者一个就是cur节点本身
    • 不用使用回溯,二叉搜索树自带方向性,可以方便的从上向下查找目标区间,遇到目标区间内的节点,直接返回
  • 题解
    • 递归

      func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
      
      	rootVal := root.Val
      	//当前节点值大了,往左子树搜索
      	if rootVal > q.Val && rootVal > p.Val {
      		left := lowestCommonAncestor(root.Left, p, q)
      		if left != nil {
      			return left
      		}
      	}
      	//当前节点值小了,往右子树搜索
      	if rootVal < q.Val && rootVal < p.Val {
      		right := lowestCommonAncestor(root.Right, p, q)
      		if right != nil {
      			return right
      		}
      	}
      	//当前节点刚好在p,q的节点值之间
      	return root
      }
      
    • 迭代

      func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
      
      	for root != nil {
      
      		if root.Val > q.Val && root.Val > p.Val {
      			//当前节点值大了, 往小了搜索
      			root = root.Left
      		} else if root.Val < q.Val && root.Val < p.Val {
      			//当前节点值小了, 往大了搜索
      			root = root.Right
      		} else {
      			//当前节点值刚好在取值范围内,直接返回
      			return root
      		}
      
      	}
      	return nil
      }
      
      

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

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

  • 思路

    • 题目条件
      • 输入数据 保证 ,新值和原始二叉搜索树中的任意节点值都不同。
    • 只要遍历二叉搜索树,找到空节点 插入元素就可以了,那么这道题其实就简单了。
  • 题解

    • 个人解法
      • 二叉搜索树是有序的
        • 只用看插入值与当前的节点值得大小关系,插在哪边即可
    func insertIntoBST(root *TreeNode, val int) *TreeNode {
    	if root == nil {//当前是空树or叶子节点直接返回新增节点
    		return &TreeNode{Val: val}
    	}
    	
    	if val < root.Val {
    		if root.Left == nil {
    			root.Left = &TreeNode{Val: val}
    			return root
    		}
    		left := insertIntoBST(root.Left, val)
    			root.Left = left
    	}
    	
    	
    	if val > root.Val {
    		if root.Right == nil {
    			root.Right = &TreeNode{Val: val}
    			return root
    		}
    		right := insertIntoBST(root.Right, val)
    			root.Right = right 
    	}
    
    	return root
    }
    
  • 递归

    func insertIntoBST(root *TreeNode, val int) *TreeNode {
    	if root == nil {
    		return &TreeNode{
    			Val: val,
    		}
    	}
    	if root.Val > val {
    		root.Left = insertIntoBST(root.Left, val)
    	} else {
    		root.Right = insertIntoBST(root.Right, val)
    	}
    	return root
    
    }
    
  • 迭代

    func insertIntoBST(root *TreeNode, val int) *TreeNode {
        if root == nil {
            return &TreeNode{Val:val}
        }
        node := root//当前操作节点
        var pnode *TreeNode//前一个父亲节点,后面追加节点标志
        for node != nil {
            if val > node.Val {
                pnode = node
                node = node.Right
            } else {
                pnode = node
                node = node.Left
            }
        }
        if val > pnode.Val {
            pnode.Right = &TreeNode{Val: val}
        } else {
            pnode.Left = &TreeNode{Val: val}
        }
        return root
    }
    

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

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

相对于 插入操作,本题就有难度了,涉及到改树的结构

题目链接/文章讲解:https://programmercarl.com/0450.删除二叉搜索树中的节点.html

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

  • 思路

    • 删除可能导致二叉搜索树结构改变
      • 区分删除节点位置
        1. 没找到节点:
          1. 不做任何处理
        2. 叶子节点:
          1. 直接删就好
        3. 左不空,右空
          1. 直接把它父节点指向它左孩子
        4. 左空,右不空
          1. 直接把它父节点指向它右孩子
        5. 左不空,右不空
          1. 任意选取一个孩子去继位
            1. 右孩子继位
              1. 把它父节点指向右孩子
              2. 原左孩子,指向右孩子的左子树的最左节点
            2. 左孩子继位
              1. 把它父节点指向右孩子
              2. 原右孩子,指向左孩子的右子树的最右节点
  • 题解

    • 递归
    func deleteNode(root *TreeNode, key int) *TreeNode {
    	if root == nil { //没找到匹配值
    		return root
    	}
    	//当前节点就是值
    	if root.Val == key {
    		//1. leaf node
    		if root.Left == nil && root.Right == nil {
    			return nil
    		}
    		//2. 左不空,右空
    		if root.Left != nil && root.Right == nil {
    			return root.Left
    		}
    		//2. 左空,右不空
    		if root.Left == nil && root.Right != nil {
    			return root.Right
    		}
    		// 选左孩子
    		cur := root.Left
        pre := cur
    		for cur != nil {
                pre = cur
    			cur = cur.Right
    		}
    		pre.Right = root.Right
    		return root.Left
    	}
    	
    	if root.Val > key {//节点值大了,去左子树删,更新左子树
    		root.Left = deleteNode(root.Left, key)
    	} else {//节点值小了,去右子树删,更新右子树
    		root.Right = deleteNode(root.Right, 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
    }
    

9. 题外话

  • 因为二叉搜索树添加节点只需要在叶子上添加就可以的,不涉及到结构的调整
  • 删除节点操作涉及到结构的调整
    • 充分考虑删除节点所在位置

  • 24
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值