题目链接
校OJ每日一题
问题重述
题目描述
输入格式
输出格式
输入输出样例
#样例1
输入:
DBEAC
ABCDE
输出:
ABDEC
大概思路
看到这一题的测试样例的时候,我第一反应还有点纳闷是不是题出错了,因为我以为可以直接就将层次遍历放进一个数组中然后根据完全二叉树的性质将二叉树存储在一个列表(数组)中,好像完全不需要中序序列,可是当我这样提交后发现是错的之后我才开始认真思考起来自己是不是哪儿想漏了。
首先,题目只告诉我们是一棵二叉树,并不是完全二叉树,也就是说,题目给的树完全有可能就是这样的
这样这棵二叉树的层次序列虽然是:ABCDEFGHI,但是他的先序序列却不是:ABDHIECFG,而是:ABDGHCEFI。
所以我就想起二叉树的定义是其每个结点的度最多为2,也就是说,其度可以为1也可以为0,所以我们还是需要用到中序序列的。
那么我们要怎么用到这个中序序列呢?
于是乎我便尝试将自己随便构造的一棵二叉树根据它的中序序列和层次序列将这棵二叉树还原出来,我们就以上面这棵二叉树为例,其中序序列为:GDHBAECFI,层次序列为ABCDEFGHI,我们尝试根据这两个序列来还原我们的二叉树
第一步,我们根据遍历层次序列的第一个结点,这个结点肯定是根节点,然后我们就在中序序列中找到这个结点的下标为4,这样我们就可以根据中序遍历的特点知道0到3是其左子树,5到8是其右子树,由于是要我们输出先序序列,所以我们就先遍历其左子树
第二步,我们就在一次遍历层次序列,找到第二个未被访问的结点B,它在中序遍历中的下标为3,是A的左孩子,然后由于它的左边是A,所以B没有右子树,但0到2是它的左子树
第三步,我们根据层次遍历找到结点C,但是C在中序序列中的下标为6,并不在0到2中,所以它不是B的左子树,故我们找层次序列的下一个结点D,D在中序序列中的下标为1,所以D是B的左子树,在中序序列中,D的左边还有下标为0的结点G,故G也是D的左子树,但是在中序序列中,结点G的左边没有未被访问的结点,它的右边是它父节点D,故我们就不用再对G往下访问了
第四步,我们就回到D结点,我们就先遍历层次序列,这个时候我们应该会先访问到C结点,但是它的下标不在D结点的右子树范围内(也就是在中序序列的下标为0到2的地方)所以我们会访问到一个未被输出过的结点H,它是D的右子树…
我们就不断的按照上述的规则进行先序遍历,最后就能输出我们想要的结果了,这个规则是不断的遍历层次序列中未被访问的结点,然后找到该节点在中序序列中的位置,先访问该节点在中序序列中左边的序列,在访问右边的序列即可,接下来请看完整代码
完整AC代码
def firstOut(left, right):
idx = -1
# 1.遍历层次遍历,找到没被访问过的结点
for i in range(len(inOrder)):
if flag[i]:
# 2.根据这个没访问过的结点在left到right中找是否存在该元素,没有就返回1,有就执行3
for j in range(left, right):
if levelOrder[i] == inOrder[j]:
# 3.在中序遍历中找到该元素的下标记录下来,并在层次遍历中将该节点标记为已访问
idx = inOrder.index(levelOrder[i])
flag[i] = 0
break
# 如果找到过就不用在往下面遍历了
if flag[i] == 0:
break
if idx != -1: # 访问到叶子结点的时候,它没有左右孩子,所以idx不会变,我们不能进行下面的步骤
print(inOrder[idx], end="")
# 4.如果该结点还存在左子树就递归
if idx > left:
firstOut(left, idx)
# 5.如果该结点还存在右子树就递归
if idx < right:
firstOut(idx + 1, right)
inOrder = input()
levelOrder = input()
flag = [1] * len(inOrder)
firstOut(0, len(inOrder))