【代码随想录——二叉树四周目】

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

相比上一周的二叉树的最近公共祖先。
二叉搜索树的最近公共祖先可以利用二叉搜索树的特性,通过寻找第一个夹在两节点中间的节点。

1.1 递归法

func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
    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
}

1.2 迭代法

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 nil
}

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

在这里插入图片描述

2.1 递归法

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 if root.Val < val{
        root.Right = insertIntoBST(root.Right,val)
    }
    return root
}

2.2 迭代法

通过迭代寻找要查找的位置,同时保留该位置的前一个指针。

func insertIntoBST(root *TreeNode, val int) *TreeNode {
    pre,rootStore := root,root
    for root != nil{
        pre = root
        if root.Val<val{
            root = root.Right
        }else{
            root = root.Left
        }   
    }
    if pre == nil{
        return &TreeNode{
            Val: val,
        }
    }else{
        if pre.Val>val{
            pre.Left = &TreeNode{
                Val: val,
            }
        }else{
            pre.Right = &TreeNode{
                Val: val,
            }
        }
    }
    return rootStore
}

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

在这里插入图片描述

3.1 递归法

方法1:使用了双指针,将要删除节点的左节点挂载到删除节点的右节点的最左节点的左节点下

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
}

3.2 迭代法

方式1:将要删除节点的左节点挂载到删除节点的右节点的最左节点的左节点下

func deleteNode(root *TreeNode, key int) *TreeNode {
    //1.未找到该key,返回nil
    if root==nil{
        return nil
    }
    //找到了要删除的节点
    if root.Val == key{
        //2.删除的节点没有孩子节点
        if root.Left==nil && root.Right==nil{
            root=nil
            return nil
        }else if root.Left==nil{ //3.删除的还没有左节点,那么返回右节点
            root = root.Right
            return root
        }else if root.Right==nil{ //4.删除的还没有右节点,那么返回左节点
            root = root.Left
            return root
        }else{//5.删除的节点有左右孩子节点
            //可以将要删除节点的左节点挂载到删除节点的右节点的最左节点的左节点下
            mostLeft := root.Right
            for mostLeft.Left!=nil{
                mostLeft = mostLeft.Left
            }
            mostLeft.Left = root.Left
            root = root.Right
            return root
        }
    }
    //要删除的节点可能在左边
    if root.Val > key{
        root.Left = deleteNode(root.Left,key)
    }
    //要删除的节点可能在右边
    if root.Val < key{
        root.Right = deleteNode(root.Right,key)
    }
    return root
}

方式2:将要删除节点的右节点的最左节点,与要删除的节点调换位置。

func deleteNode(root *TreeNode, key int) *TreeNode {
	// 特殊情况处理
	if root == nil {
		return root
	}
    if key<root.Val{
        root.Left = deleteNode(root.Left,key)
    }else if root.Val<key{
        root.Right = deleteNode(root.Right,key)
    }else{
        //能进到这里说明已经找到需要删除的节点了
        if root.Right == nil{
            return root.Left
        }else if root.Left == nil{
            return root.Right
        }else{
            //说明两个子节点均存在
            minnode := root.Right
            for minnode.Left != nil {
                minnode = minnode.Left
            }
            root.Val = minnode.Val
            root.Right = deleteNode1(root.Right)
            return root
        }
    }
    return root
}

func deleteNode1(root *TreeNode)*TreeNode {
    if root.Left==nil{
        tempR := root.Right
        root.Right = nil
        return tempR
    }
    //递归查找删除点
    root.Left = deleteNode1(root.Left)
    return root
}

4. 修剪二叉搜索树

在这里插入图片描述

4.1 递归法

func trimBST(root *TreeNode, low int, high int) *TreeNode {
    if root==nil{
        return root
    }
    if root.Val<low{
        return trimBST(root.Right,low,high)
    }
    if root.Val>high{
        return trimBST(root.Left,low,high)
    }
    root.Left = trimBST(root.Left,low,high)
    root.Right = trimBST(root.Right,low,high)
    return root
}

4.2 迭代法

func trimBST(root *TreeNode, low int, high int) *TreeNode {
    if root==nil{
        return root
    }
    // 处理root,让root移动到[low,high]范围内,注意是左闭右闭
    for root != nil && (root.Val < low || root.Val > high){
        if root.Val < low{
            root = root.Right
        } else {
            root = root.Left
        }
    }
    cur := root
    // 此时root已经在[low,high]范围内,处理左孩子元素小于 low 的情况(左节点是一定小于 root.Val,因此天然小于 high)
    for cur != nil{
        for cur.Left != nil && cur.Left.Val < low{
            cur.Left = cur.Left.Right
        }
        cur = cur.Left
    }
    cur = root
    // 此时 root 已经在[low, high] 范围内,处理右孩子大于 high 的情况
    for cur != nil{
        for cur.Right != nil && cur.Right.Val >high{
            cur.Right = cur.Right.Left
        }
        cur = cur.Right
    }
    return root
}

5. 将有序数组转换为二叉搜索树

5.1 本题

在这里插入图片描述

5.1.1 递归法

每次取数组中间的数作为节点,利用双指针。

func sortedArrayToBST(nums []int) *TreeNode {
    l,r := 0,len(nums)-1
    return createTreeNode(nums,l,r)
}

func createTreeNode(nums []int, l,r int)*TreeNode{
    if l>r{
        return nil
    }
    mid := (l+r)/2
    root := &TreeNode{Val:nums[mid]}
    root.Left = createTreeNode(nums,l,mid-1)
    root.Right = createTreeNode(nums,mid+1,r)
    return root
}

//更加优雅的写法
func sortedArrayToBST(nums []int) *TreeNode {
    if len(nums) == 0 {    //终止条件,最后数组为空则可以返回
        return nil
    }
    idx := len(nums)/2
    root := &TreeNode{Val: nums[idx]} 
     
    root.Left = sortedArrayToBST(nums[:idx])
    root.Right = sortedArrayToBST(nums[idx+1:])

    return root
}

6. 把二叉搜索树转换为累加树

在这里插入图片描述

var pre int
func convertBST(root *TreeNode) *TreeNode {
    pre = 0
    traversal(root)
    return root
}

func traversal(cur *TreeNode){
    if cur == nil {
        return
    }
    traversal(cur.Right)
    cur.Val += pre
    pre = cur.Val
    traversal(cur.Left)
}

7. 额外题目

7.1 从中序与后序遍历序列构造二叉树

在这里插入图片描述

func buildTree(inorder []int, postorder []int) *TreeNode {
	idxMap := map[int]int{}
	for i, v := range inorder {
		idxMap[v] = i
	}
	return createNode(0, len(inorder)-1, &postorder, idxMap)
}

func createNode(inorderLeft, inorderRight int, postorder *[]int, idxMap map[int]int) *TreeNode {
	// 无剩余节点
	if inorderLeft > inorderRight {
		return nil
	}
	// 后续遍历的末尾元素即为当前子树的根节点
	length := len(*postorder)
	val := (*postorder)[length-1]
	*postorder = (*postorder)[:length-1]
	root := &TreeNode{Val: val}
	// 根据 val 在中序遍历的位置,将中序遍历划分成左右两颗子树
	// 由于我们每次都从后序遍历的末尾取元素,所以要先遍历右子树再遍历左子树
	inorderRootIndex := idxMap[val]
	root.Right = createNode(inorderRootIndex+1, inorderRight, postorder, idxMap)
	root.Left = createNode(inorderLeft, inorderRootIndex-1, postorder, idxMap)
	return root
}

7.2 从中序与前序遍历序列构造二叉树

在这里插入图片描述

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func buildTree(preorder []int, inorder []int) *TreeNode {
    idxMap := map[int]int{}
	for i, v := range inorder {
		idxMap[v] = i
	}
    return createTree(0, len(inorder)-1, &preorder, idxMap)
}

func createTree(inorderLeft,inorderRight int,preorder *[]int,idxMap map[int]int)*TreeNode{
    if inorderLeft>inorderRight{
        return nil
    }
    val := (*preorder)[0]
    *preorder = (*preorder)[1:]
    index := idxMap[val]
    root := &TreeNode{Val:val}
    root.Left = createTree(inorderLeft,index-1,preorder,idxMap)
    root.Right = createTree(index+1,inorderRight,preorder,idxMap)
    return root
}

7.3 最大二叉树

在这里插入图片描述

func constructMaximumBinaryTree(nums []int) *TreeNode {
    if len(nums)==0{
        return nil
    }
    maxIndex := findMaxIndex(nums)
    root := &TreeNode{Val:nums[maxIndex]}
    root.Left = constructMaximumBinaryTree(nums[:maxIndex])
    root.Right = constructMaximumBinaryTree(nums[maxIndex+1:])
    return root
}

func findMaxIndex(nums []int)int{
    maxIndex := 0
    for i:=1;i<len(nums);i++{
        if nums[i]>nums[maxIndex]{
            maxIndex = i
        }
    }
    return maxIndex
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值