题目:
【问题描述】输入一个整数数组,判断该数组是不是某二元查找树的后序遍历的结果。如果是返回true,否则返回false。
【输入形式】输入任意长度的数组,数字之间空格分开
【输出形式】true 或者 false
【样例输入】输入 5 7 6 9 11 10 8
【样例输出】true
【样例说明】由于这一整数序列是如下树的后序遍历结果:
8
/ \
6 10
/ \ / \
5 7 9 11
因此返回true。
【评分标准】暴力求解法不得分。
思路:
- 这个题我做的时候没有绕过来弯,以为根据排序可以得到中序结构,有了后续和中序可以建立一个树,然后判断这个树是不是一个二叉排序树。但这个思路是错的
- 正确的思路其实很简单:
检测后缀表达式,最后一个为根,搜索树后序遍历数组,从数组头到第一个比根大的节点是左孩子,后面右孩子必须全大于根,递推,如果右孩子不大于根,说明是错的后缀遍历 pre(int las[], int start, int index)
这个函数是一个递归函数,start - index是此时要遍历的后缀范围,index是这个范围的根,比如5 7 6 9 11 10 8
刚开始,start = 0, index = 6
,其中las[index]为这个范围的根find_min(int las[], int start, int index)
这个函数是要找到第一个大于或者等于根的结点,然后用这个点来进行范围的划分 — 实质上就是对根进行左右子结点的拆分- 到最后进行对左右子范围的递归
代码:
#include <stdio.h>
#include <stdlib.h>
int find_min(int las[], int start, int index) {
for (int i = start; i < index; i++) {
if (las[i] >= las[index]) {
return i;
}
}
}
int pre(int las[], int start, int index) {
if (start < index) {
int end = find_min(las, start, index);
for (int i = end; i < index; i++) {
if (las[i] < las[index]) {
return 0;
}
}
pre(las, start, end - 1);
pre(las, end, index - 1);
}
return 1;
}
int main() {
int las[40];
int l_num = 0;
do {
scanf("%d", &las[l_num++]);
} while (getchar() != '\n');
if (pre(las, 0, l_num - 1)) {
printf("true");
}
else
printf("false");
return 0;
}