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

所有这些二叉树都有着相同的前序遍历和后序遍历,但中序遍历却不相同
输入:
输A数据共两行,第一行表示该二叉树的前序遍历结果s1,第二行表示该二叉树的后序遍历结果s2。
输出:
输出可能的中序遍历序列的总数,结果不超过长整型数。
例:
输入: 输出:
abc 4
cba
分析思路:
已知中序遍历和前序遍历或后序遍历,可以唯一确定一棵二叉树。而已知前序遍历和后续遍历无法唯一确定一颗二叉树。
所以,已知前序遍历和后序遍历情况下,中序遍历不同,则二叉树具有不同的结构。求符合前序遍历和后序遍历的所有可能的树的数量。
原来我的思路是,前序构造所有可能的二叉树,然后后续遍历这些树,每一次后序遍历符合,就把数量加一。但是,根据前序遍历构造二叉树所有可能的情况是十分困难繁琐的,我甚至怀疑有没有这么一种方法。而且,就算构造出来,空间复杂度和时间复杂度都是很高的,不像是一个好方法。
而正确的分析思路是:
对于这两种结构:
a a
b b c
c
左边一种有两个单子叶节点,这两个节点接在左右都是不同的情况,所有可能的树数量是(单子叶节点数)2,对于左边的情况,就是22=4;
对于右边一种情况,双子叶,这是固定死的,不能通过节点改变产生不同的树了。
而一颗二叉树,无非是单子叶和双子叶的结合,综合上两种情况,得出:可能的二叉树数量=(单子叶节点数)2
我们能知道的只有前序遍历和后序遍历,也没法通过这个构造二叉树。那就从前序遍历和后序遍历本身看看,前序遍历顺序是根左右,后序遍历是左右根。
对于左边情况,前序:abc 后序:cba
对于右边情况,前序:abc 后序:bca
对于单子叶节点,正序遍历出现bc,则后序遍历必出现cb,而对于右边双子叶情况,前序出现bc,则后序可能出现b***c,出现***是因为读取了c节点子叶。而单子叶节点,下一个就是子叶,不存在***,所以,前序出现bc,后序必出现cb。反之,前序出现bc,后序出现cb,就找到了一个单子叶节点。整个问题就变成了字符匹配了。
代码:
#include<iostream> using namespace std; int main() { string str1, str2; cin >> str1 >> str2; int lenth = str1.length(); //求解字符串长度,防止非法访问 long sum = 1; for (int i = 1; i < lenth; i++) { for (int j = 0; j < lenth - 1; j++) { if (str1[i] == str2[j] && str1[i - 1] == str2[j + 1]) sum *= 2; //找到一个单子叶节点,总数乘以2 } } cout << sum << endl; return 0; }
感想:
这就是一道二叉树遍历的算法题了,复杂的思考过程,凝练成几行简单的代码。这些简单的代码,一个代码新手也能看懂。如果这是一道字符匹配的题,新手也能写出这样的代码。但这是一道算法题,让人无从下手,让人没有思路,写代码容易,找思路,难上加难。算法往往涉及到一些非常规的思维,逆向思维,用最简单的代码解决最复杂的问题。

浙公网安备 33010602011771号