题目链接:P1030 [NOIP2001 普及组] 求先序排列 - 洛谷 | 计算机科学教育新生态

思路:                   

1.先确定跟节点
2.根据根节点,划分出左右子树

中:BADC
后:BDCA

分析:

根据后序遍历,整个序列里最后一个元素,可以看出A是根节点,再来看中序遍历,根据根结点A,我们可以划分出左右两个区域,左子树是B,右子树是DC,再转到后序遍历,也可以划分出左右两个区域,左子树是B,右子树是DC

                                  

根据前序遍历,先输出根结点A,在去处理左子树,可以观察一下左子树的信息和刚开始这棵树的信息是一样的,当分析出左子树信息的时候,我拿到的是他中序遍历的结果和后序遍历的结果,此时划分左右子树发现他只有根节点B,所以直接输出个B就行,此时左子树处理完毕,回到右子树上,在后序遍历里面先确定根结点,输出C,在去中序遍历里面划分区间,左子数是D,右子树是不存在的,所以又划分出来了中序遍历和后序遍历都是D,此时输出D,前序遍历的结果就是ABCD

我们可以发现,无论是哪个区域,我们处理的方法都是一样的,依照后序遍历确定根节点,根据根节点划分出左右子树,所以可以用递归实现整个流程

递归细节:

传参:在题目里面,我们首先拿到的是两个字符串,在第一个问题里面,我们处理的是整个字符串,当递归到左右子树的时候,我们拿的字符串的一部分,因此在传参的时候,你只需告诉我原字符串要处理哪一段就行了,就可以定四个变量,让l1指向中序遍历要处理的左端点,r1指向中序遍历要处理的右端点, l2后序遍历要处理的左端点, r2 后序遍历要处理的右端点

递归处理划分左右子树:假设根节点p落在第三个位置,在中序遍历里要处理的区间是l1到p-1,右子树要处理的区域是p+1到r1,根据中序遍历,我们可以知道左区域的长度,p-1-l1+1=p-l1,所以后序遍历的左区间是l2到l2+p-l1-1,右区间的左端点是l2+p-l1-1+1=l2+p-l1,有端点是r2-1

递归出口:当区间长度是1的时候,r1指针会跑到l1的左边,此时的区间是不合法的,就要递归返回

代码实现:

#include <iostream>
#include <string>
using namespace std;

string a, b;

void dfs(int l1, int r1, int l2, int r2)
{
    // 递归出口
    // 当区间不合法时,返回
    if (l1 > r1) return;

    // 1. 确定根节点 - b[r2]
    cout << b[r2];

    int p = l1;
    while (a[p] != b[r2]) p++; // p 用来标记中序遍历中根节点的位置

    // 2. 划分左右子树
    dfs(l1, p - 1, l2, l2 + p - l1 - 1); // 递归处理左子树
    dfs(p + 1, r1, l2 + p - l1, r2 - 1); // 递归处理右子树
}

int main()
{
    cin >> a >> b;
    dfs(0, a.size() - 1, 0, b.size() - 1);

    return 0;
}

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐