首页 > 其他分享 >不同序构造二叉树

不同序构造二叉树

时间:2024-03-01 20:56:26浏览次数:18  
标签:dfs idx 不同 Counter 构造 二叉树 l1 root order

一、根据前序与中序构造二叉树

  • 前序遍历:确定根节点root,最左端的节点即为根节点
  • 中序遍历:确定根节点左右两边的节点,通过计算左右两边节点集合的大小
  • 对root左节点集合与右节点集合执行重复操作,不断确定小集合的根节点,最终可构造出一整棵二叉树
  • 树的存储可以采用定义类或结构体,这里为方便存储,采用哈希表left存储左节点,right存储右节点
from collections import Counter
in_order = [1,2,3,4,5,6,7]
pre_order = [4,1,3,2,6,5,7]
idx = Counter()
for i, x in enumerate(in_order):
    idx[x] = i
left, right = Counter(), Counter()
def dfs(l1: int, r1: int, l2: int, r2: int) -> int:
    if l1 > r1:
        return 0
    root = pre_order[l2]
    id = idx[root]
    left[root] = dfs(l1, id - 1, l2 + 1, l2 + (id - l1))
    right[root] = dfs(id + 1, r1, l2 + (id - l1) + 1, r2)
    return root

root = dfs(0, n - 1, 0, n - 1)

二、根据后序与中序构造二叉树

其方法同上

from collections import Counter
in_order = [1,2,3,4,5,6,7]
post_order = [2,3,1,5,7,6,4]
idx = Counter()
for i, x in enumerate(in_order):
    idx[x] = i
left, right = Counter(), Counter()
def dfs(l1: int, r1: int, l2: int, r2: int) -> int:
    if l1 > r1:
        return 0
    root = post_order[r2]
    id = idx[root]
    left[root] = dfs(l1, id - 1, l2, l2 + (id - l1) - 1)
    right[root] = dfs(id + 1, r1, l2 + (id - l1), r2 - 1)
    return root

root = dfs(0, n - 1, 0, n - 1)

三、根据层序与中序构造二叉树

  • 根据层序遍历的性质,层序数组中的第一个元素一定是根节点root(在中序数组中的下标为idx)
  • 找到root,再结合中序数组,就可以找到,根节点的左儿子集合与右儿子集合
  • 找到在左儿子集合(l,idx - 1)中出现且按照层序数组中的顺序出现的序列,其序列中的第一个元素就是下一个根节点
  • 右儿子集合(idx + 1,r)同理
from collections import Counter

level_order = [4, 1, 6, 3, 5, 7, 2]
in_order = [1, 2, 3, 4, 5, 6, 7]

n = len(in_order)
mp = Counter()
for i, x in enumerate(in_order):
    mp[x] = i

left, right = Counter(), Counter()


def dfs(l, r):
    if l > r:
        return 0
    root = 0
    for x in level_order:
        if l <= mp[x] <= r:
            root = x
            break
    idx = mp[root]
    left[root] = dfs(l, idx - 1)
    right[root] = dfs(idx + 1, r)
    return root


def pre_order(root):
    if root:
        print(root, end=' ')
        pre_order(left[root])
        pre_order(right[root])

root = dfs(0,n - 1)
pre_order(root)  # 4 1 3 2 6 5 7

四、根据前序与后序构造二叉树

  • 前序与后序可以判别根节点,但去无法判别左子树与右子树

  • 因此,如果只根据前序与后序是无法构造出唯一的二叉树的(除非所有的非叶子节点都有两个儿子,这样就不会混淆)

  • 举例

既然不可以唯一构造,那我们构造出其中 一种 即可!

方案一:

from collections import Counter
#
pre_order = [4,1,3,2,6,5,7]
post_order = [2,3,1,5,7,6,4]

# pre_order = [1,2,4,5,3,6,7]
# post_order = [4,5,2,6,7,3,1]
n = len(pre_order)

left, right = Counter(), Counter()


def dfs(a,b):
    if not a:
        return 0
    root = a[0]
    if len(a) == 1:
        return root
    idx = b.index(a[1])
    left[root] = dfs(a[1:idx + 2],b[:idx + 1])
    right[root] = dfs(a[idx + 2:],b[idx + 1:-1])
    return root


def in_order(root):
    if root:
        in_order(left[root])
        print(root, end=' ')
        in_order(right[root])

print(dfs(pre_order,post_order))
in_order(dfs(pre_order,post_order))

方案二

from collections import Counter

pre_order = [4,1,3,2,6,5,7]
post_order = [2,3,1,5,7,6,4]

n = len(pre_order)
mp = Counter()
for i, x in enumerate(post_order):
    mp[x] = i

left, right = Counter(), Counter()


def dfs(l1, r1,l2,r2):
    if l1 > r1:
        return 0
    root = pre_order[l1]
    if l1 == r1:
        return root
    idx = mp[pre_order[l1 + 1]]
    left[root] = dfs(l1 + 1,l1 + 1 + idx - l2,l2,idx)
    right[root] = dfs(l1 + 1 + idx - l2 + 1,r1,idx + 1,r2 - 1)
    return root


def in_order(root):
    if root:
        in_order(left[root])
        print(root, end=' ')
        in_order(right[root])

print(dfs(0,n - 1,0,n - 1))
in_order(dfs(0, n - 1,0,n - 1))

拓展

已知二叉树的前序遍历与后序遍历,求可以构造的二叉树的种类数?【确认根节点后,枚举左儿子节点集合长度!】

pre_order = [4,1,3,2,6,5,7]
post_order = [2,3,1,5,7,6,4]
n = len(pre_order)

def dfs(l1,r1,l2,r2):
    if l1 > r1:
        return 1
    if pre_order[l1] != post_order[r2]:
        return 0
    cnt = 0
    for i in range(l1,r1 + 1):
        left_cnt = dfs(l1 + 1,i,l2,l2 + i - l1 - 1)
        right_cnt = dfs(i + 1,r1,l2 + i - l1 - 1 + 1,r2 - 1)
        if left_cnt > 0 and right_cnt > 0:
            cnt += left_cnt * right_cnt
    return cnt

print(dfs(0,n - 1,0,n - 1))

标签:dfs,idx,不同,Counter,构造,二叉树,l1,root,order
From: https://www.cnblogs.com/gebeng/p/18047904

相关文章

  • 94. 二叉树的中序遍历c
    /***Definitionforabinarytreenode.*structTreeNode{*intval;*structTreeNode*left;*structTreeNode*right;*};*//***Note:Thereturnedarraymustbemalloced,assumecallercallsfree().*/voidinorder(structTre......
  • 145. 二叉树的后序遍历c
    /***Definitionforabinarytreenode.*structTreeNode{*intval;*structTreeNode*left;*structTreeNode*right;*};*//***Note:Thereturnedarraymustbemalloced,assumecallercallsfree().*/voidpostorder(structT......
  • 144. 二叉树的前序遍历c
    /***Definitionforabinarytreenode.*structTreeNode{*intval;*structTreeNode*left;*structTreeNode*right;*};*//***Note:Thereturnedarraymustbemalloced,assumecallercallsfree().*/voidpreorder(structTr......
  • leedcode 二叉树的前序遍历
    递归法:classSolution:def__init__(self):#初始化一个实例变量res用于存储前序遍历结果self.res=[]defpreorderTraversal(self,root:Optional[TreeNode])->List[int]:#如果根节点存在ifroot:#检查根......
  • 面向对象—【类与对象】【类的定义与对象创建】【对象的使用】【方法创建与使用】【方
    面向对象基础篇我们在前面已经学习了面向过程编程,也可以自行编写出简单的程序了。我们接着就需要认识面向对象程序设计(ObjectOrientedProgramming)它是我们在Java语言中要学习的重要内容,面向对象也是高级语言的一大重要特性。面向对象是新手成长的一道分水岭,有的人秒懂,有的人......
  • 面向对象—【类与对象】【类的定义与对象创建】【对象的使用】【方法创建与使用】【方
    @目录面向对象基础篇类与对象类的定义与对象创建对象的使用方法创建与使用方法进阶使用构造方法源码:Giteehttps://gitee.com/drip123456/java-seGIthubhttps://github.com/Drip123456/JavaSE专栏:JavaSE笔记专栏面向对象基础篇我们在前面已经学习了面向过程编程,也可以自......
  • 以解析csv数据为例,讨论string、char[]、stream 不同类型来源是否能进行高性能读取解析
    篇幅较长,所以首先列举结果,也就是我们的目的核心目的为探索特定场景对不同类型数据进行统一抽象,并达到足够高性能,也就是一份代码实现,对不同类型数据依然高性能以下为结果,也就是我们的目的:对1w行csv数据的string进行RFC4180csv标准进行解析,string类型csv应该比StringRea......
  • 英语语法1,词性:不同的词语可以被归类为不同的词性
    不同的词语可以被归类为不同的词性名词(Noun):名词是用来表示人、事物、地方或概念的词语。名词可以是具体的(如"猫"、"桌子")或抽象的(如"爱"、"幸福")。名词可以用来作为主语、宾语、表语等。代名词(Pronoun):代名词是用来替代名词的词语,以避免重复使用特定的名词。代名词包括......
  • abc305_f (构造实现)
    首先考虑正常的怎么做,就是一遍dfs,是\(O(n)\)的,然而这题在到达每一个点时都要输出它的下一个点才能到达下一个点,同时看到这个\(2n\)觉得不对劲,自然想到走过去走回来,耗2n代码实现还是有点东西的,走过去好搞,但走回来时怎么办呢。我们想到dfs是一个栈,所以在要退出时输出就可以了#inc......
  • pd.ExcelWriter 实现数据写入不同sheet
    pd.ExcelWriter将数据写入不同sheet当结合for循环使用时,需注意放在for循环前面以下写法,仅生成一个sheet,原因在于pd.ExcelWriter的mode默认是w,每次for循环写入数据都会对原有的数据进行覆盖,最终只会生成一个sheet。importpandasaspddf1=pd.DataFrame([["AAA","BBB"]],......