刷题:删除二叉树中的节点(Go)

步骤

1. 寻找节点的父节点,有三种情况:

  • 目标节点即根节点
  • 目标节点非根节点
  • 目标节点不存在

2. 删除节点

  • 如果目标节点是根节点:
    将根节点左子树移到右子树最左侧,返回右子树
  • 如果目标节点非根节点:
    • 如果目标节点没有右子树,直接父节点对应指针指向左子树,返回树
    • 如果目标节点有右子树,将左子树移到右子树最左侧,父节点对应指针指向右子树,返回树
  • 目标节点不存在,返回树
/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func deleteNode(root *TreeNode, key int) *TreeNode {
    if root == nil {
        return root
    }
    // 寻找目标节点的父节点位置,并标记目标节点是父节点的左还是右,0左1右,-1表示节点不存在, -2表示目标是根
    preNode,flags := findNode(root,key)
    if flags == -1{
        return root
    }else if flags == -2 {
        if preNode.Left != nil && preNode.Right != nil {
            rln := preNode.Right
            for rln.Left != nil {
                rln = rln.Left
            }
            rln.Left = preNode.Left
            return preNode.Right
        }
        if preNode.Left != nil {
            return preNode.Left
        }else{
            return preNode.Right
        }
    }
    // 获取目标节点
    var node *TreeNode
    if flags == 0{
        node = preNode.Left
    }else if flags == 1 {
        node = preNode.Right
    }else{
        return root
    }

    // 按目标左右节点分布情况决定如何删除目标节点
    ln := node.Left
    rn := node.Right
    // 1. 没有左右节点, 直接删除
    if ln == nil && rn == nil {
        if flags == 0{
            preNode.Left = nil
        }else if flags == 1 {
            preNode.Right = nil
        }
        return root
    }

    // 2. 只有左子节点,左子节点顶替目标节点
    if ln != nil && rn == nil {
        if flags == 0{
            preNode.Left = ln
        }else if flags == 1 {
            preNode.Right = ln
        }
        return root
    }

    // 3. 只有右子节点,右子节点顶替目标节点
    if ln == nil && rn != nil {
        if flags == 0{
            preNode.Left = rn
        }else if flags == 1 {
            preNode.Right = rn
        }
        return root        
    }

    // 4. 左右节点都存在
    if ln != nil && rn != nil {
        // 左子树加入右子树,放在右子树最左侧
        rnl := rn
        for rnl.Left!=nil {
            rnl= rnl.Left
        }
        rnl.Left = ln
        // 右子节点顶替目标节点
        if flags == 0{
            preNode.Left = rn
        }else if flags == 1 {
            preNode.Right = rn
        }
        return root        
    }
    
    return root
}

func findNode(root *TreeNode, key int) (*TreeNode,int) {
    if root.Val == key{return root,-2}
    var pre *TreeNode
    for {
        if key > root.Val {
            if root.Right != nil {
                pre = root
                root = root.Right
                continue
            }else{
                return nil,-1
            }
        }
        if key < root.Val {
            if root.Left != nil {
                pre = root
                root = root.Left
                continue
            }else{
                return nil,-1
            }
        }
        if root == pre.Left{
            return pre,0  // 左子节点
        }else{
            return pre,1  // 右子节点
        }
    }
}

代码还能简化…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值