题目
我们可以把由“0”和“1”组成的字符串分为三类:全“0”串称为B串,全“1”串称为I串,既含“0”又含“1”的串则称为F串。FBI树是一种二叉树,它的结点类型也包括F结点,B结点和I结点三种。由一个长度为2N的“01”串S可以构造出一棵FBI树T,递归的构造方法如下:
1.T的根结点为R,其类型与串S的类型相同;
2.若串S的长度大于1,将串S从中间分开,分为等长的左右子串S1和S2;由左子串S1构造R的左子树T1,由右子串S2构造R的右子树T2。
现在给定一个长度为2N的“01”串,请用上述构造方法构造出一棵FBI树,并输出它的后序遍历序列。
输入描述:第一行是一个整数 N ( 0 ≤ N ≤ 10 ) N(0 \le N \le 10)N(0≤N≤10),第二行是一个长度为2^N的 “01”串。
输出描述:一个字符串,即 FBI 树的后序遍历序列。
输入样例:
3
10001011
输出样例:
IBFBBBFIBFIIIFF
题目思路
由题目可得以下信息:
1.给定“01”字符串可以构造FBI树,长度为2^N ==> 可以联想到二叉树每层节点数2^(k-1);
2.FBI树(T)是由三种结点类型(I,B,F)构成;
3.根结点R与字符串S类型相同,以输入样例为例即,F类型;
4.字符串S左右中间分开,依次中间分开,直到最后只有一个字符(递归调用最后一层,赋值);
5.后序遍历输出二叉树。
因此,该题分为三块:输入,递归函数,二叉树后续输出函数。
主要理解在递归:将给定2^N长度的字符串,依次中间分割,引入字符串下标,左右子串进行递归调用,最终一个字符不可再分,左右下标相等;此时回溯各个结点的类型,结点位置的关系:父节点p ,左右子节点:2*p ,2*p+1, 将各个结点类型存储在二叉树的数组,即也要引入一个参数p来记录层数表示层与层调用和回溯。
递归也分三块:递归到最后一层进行并填入最后一层结点的类型,递归部分,回溯对各个结点的左右结点判断。
代码理解
##p:代表当前根节点,并用来表示左右子节点:2*P,2*P+1用于下一次递归也
##就是p的值:build_FBI(p,left,right)(p=2*P)
##left,right用来表示s字符串最左最右的下标
##s[left],s[right]字符串
def build_FBI(p,left,right):
##递归到最深处例如当左边left=0,right=1,mid=0,最后一次递归就是left=0,right=0;left=1,right=1:
if left==right:
if s[right]=='1':
tree[p]='I'
else: tree[p]='B'
return
##不到最深处继续递归,将字符串分割,p往下表示子节点:
mid=(left+right)//2
build_FBI(2*p,left,mid)
build_FBI(2*p+1,mid+1,right)
##直到left==right;此时对最下层的tree[P]填充,再一次向上回溯,完整tree
if tree[2*p]=='I' and tree[2*p+1]=='I':
tree[p]='I'
elif tree[2*p]=='B' and tree[2*p+1]=='B':
tree[p]='B'
else: tree[p]='F'
##二叉树输出,后序:左右父
def postorder(p):
if tree[2*p] !=' ':postorder(2*p)##先把左递归,完毕之后才可以进行右递归
if tree[2*p+1] !=' ' :postorder(2*p+1)
##直到最里一层输出,回溯,输出
print(tree[p],end=' ')
n=int(input())
s=input()
tree=[' ']*4400
build_FBI(1,0, len(s)-1)
postorder(1)