2021-06-12:已知一棵搜索二叉树上没有重复值的节点,现在有一个数组arr,是这棵搜索二叉树先序遍历的结果。请根据arr生成整棵树并返回头节点。

Posted 福大大架构师每日一题

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021-06-12:已知一棵搜索二叉树上没有重复值的节点,现在有一个数组arr,是这棵搜索二叉树先序遍历的结果。请根据arr生成整棵树并返回头节点。相关的知识,希望对你有一定的参考价值。

2021-06-12:已知一棵搜索二叉树上没有重复值的节点,现在有一个数组arr,是这棵搜索二叉树先序遍历的结果。请根据arr生成整棵树并返回头节点。

福大大 答案2021-06-12:

先序遍历+中序遍历(搜索树)+不重复值=唯一的二叉树。

解法一
自然智慧。第0位置为根节点,遍历1~N-1位置,找到比0位置大的,那就是属于根的右节点。时间复杂度是O(N**2)。

解法二
单调栈。时间复杂度是O(N)。

代码用golang编写。代码如下:

package main

import (
    "container/list"
    "fmt"
)

func main() {
    arr := []int{8, 5, 1, 7, 10, 12}
    ret1 := bstFromPreorder1(arr)
    fmt.Println("----自然智慧----")
    printTree(ret1)

    fmt.Println("")
    fmt.Println("----单调栈----")
    ret2 := bstFromPreorder2(arr)
    printTree(ret2)
}

type TreeNode struct {
    Val   int
    Left  *TreeNode
    Right *TreeNode
}

func printTree(head *TreeNode) {
    if head == nil {
        return
    }
    queue := list.New()
    queue.PushBack(head)
    for queue.Len() > 0 {
        before := queue.Front()
        queue.Remove(before)
        beforeNode := before.Value.(*TreeNode)
        fmt.Print(beforeNode.Val, "\\t")
        if beforeNode.Left != nil {
            queue.PushBack(beforeNode.Left)
        }
        if beforeNode.Right != nil {
            queue.PushBack(beforeNode.Right)
        }
    }
}

func bstFromPreorder1(pre []int) *TreeNode {
    return process1(pre, 0, len(pre))
}

func process1(pre []int, start int, endnot int) *TreeNode {
    if start == endnot {
        return nil
    }
    if start+1 == endnot {
        return &TreeNode{Val: pre[start]}
    }
    i := start + 1
    for ; i < endnot; i++ {
        if pre[start] < pre[i] {
            break
        }
    }
    head := &TreeNode{Val: pre[start]}
    head.Left = process1(pre, start+1, i)
    head.Right = process1(pre, i, endnot)
    return head
}

// 已经是时间复杂度最优的方法了,但是常数项还能优化
func bstFromPreorder2(pre []int) *TreeNode {
    if len(pre) == 0 {
        return nil
    }
    N := len(pre)
    nearBig := make([]int, N)
    for i := 0; i < N; i++ {
        nearBig[i] = -1
    }
    stack := list.New()
    for i := 0; i < N; i++ {
        for stack.Len() > 0 && pre[stack.Back().Value.(int)] < pre[i] {
            nearBig[stack.Back().Value.(int)] = i
            stack.Remove(stack.Back())
        }
        stack.PushBack(i)
    }
    return process2(pre, 0, N-1, nearBig)
}

func process2(pre []int, L int, R int, nearBig []int) *TreeNode {
    if L > R {
        return nil
    }
    firstBig := twoSelectOne(nearBig[L] == -1 || nearBig[L] > R, R+1, nearBig[L])
    head := &TreeNode{Val: pre[L]}
    head.Left = process2(pre, L+1, firstBig-1, nearBig)
    head.Right = process2(pre, firstBig, R, nearBig)
    return head
}

func twoSelectOne(c bool, a int, b int) int {
    if c {
        return a
    } else {
        return b
    }
}

执行结果如下:
图片


左神java代码

以上是关于2021-06-12:已知一棵搜索二叉树上没有重复值的节点,现在有一个数组arr,是这棵搜索二叉树先序遍历的结果。请根据arr生成整棵树并返回头节点。的主要内容,如果未能解决你的问题,请参考以下文章

NC60 判断一棵二叉树是否为搜索二叉树和完全二叉树

数据结构与算法(周测4-树总结)

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表

如何获取从根到二叉树上给定节点的路径?

判断一棵树是否是完全二叉树