P1229 遍历问题

P1229 遍历问题


题目描述

我们都很熟悉二叉树的前序、中序、后序遍历,在数据结构中常提出这样的问题:已知一棵二叉树的前序和中序遍历,求它的后序遍历,相应的,已知一棵二叉树的后序遍历和中序遍历序列你也能求出它的前序遍历。然而给定一棵二叉树的前序和后序遍历,你却不能确定其中序遍历序列,考虑如下图中的几棵二叉树:

img

所有这些二叉树都有着相同的前序遍历和后序遍历,但中序遍历却不相同。

输入格式

输A数据共两行,第一行表示该二叉树的前序遍历结果s1,第二行表示该二叉树的后序遍历结果s2。

输出格式

输出可能的中序遍历序列的总数,结果不超过长整型数。

输入输出样例

输入 #1

abc                           
cba

输出 #1

4

解题思路

	a	b	c
	c	b	a

首先得明确几个点:

  • 因为前序遍历,头节点a的下一个点一定是他的子节点b 后序遍历,对于前序遍历的b,一定是以b为头节点的子树 的后序遍历的最后一个位置。 (也就是对应着第一个序列的b的位置,和第二个序列的b位置)
  • 对于序列永远都是左子树的各节点遍历完,才到右子树的各节点
  • 如果第二个序列以b结尾,之后就再也没有节点了 说明a节点,只有一个子节点,上面的样例就是这种情况。

那么给一个不是这种情况的序列,找个规律:
	a	b	c
	b	c	a   这个序列的a就有两个子节点 

  • 采用第二个的结论,当只有一个子节点b的时候这个子节点无论在父节点a 的左孩子,还是右孩子,对前序和后序遍历都不会有影响 所以这里就有 两种情况(k==2)了;那么有两个子节点的时候,根本动不了,所以只有一种情况
// @Class name:P1229
// @Description ToDo
// @Author: Amadues
// @Date 2022/1/16 8:43
// @Version 0.0
#define io_opt ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
using namespace std;
int main()
{
    io_opt;
    int ans = 0;
    string s1 , s2;
    cin >> s1 >> s2;
    for (int i = 0 ; i < s1.size() ; i++)
    {
        for (int j = 1 ; j < s2.size() ; j++)
        {
            if (s1[i] == s2[j] && s1[i + 1] == s2[j - 1])
            {
                ans++;
            }
        }
    }
    cout << (1<<ans) << endl;
    return 0;
}

我们首先可以明确的是,在一棵树上若有一个结点是只有一个子结点的那么这个子结点在左在右不影响先序后序的遍历顺序,那么总树数就要乘以2(乘法原理,这个子结点有两种选择,一种成为左子树,一种成为右子树),为了找到只有一个子结点的结点数,我们继续。。

我们可以得到一个规律,在先序遍历中某一元素A的后继元素B,如果在后序遍历中A的前驱元素是B,那么A只有一个子树,问题即得解

楼下提醒了我,先序遍历中,如果A只有一个子树B,那么在先序遍历中A一定在B前,在后序遍历中B一定在A前,根据先序遍历和后序遍历的定义和性质可以看出,那么这样想到了的话,实现起来就简单了,大概是O(n2)可以跑过

posted @ 2022-01-16 08:57  亚托莉的亚托莉  阅读(135)  评论(0)    收藏  举报