文章首发于公众号“面鲸“,欢迎关注~I’m waiting for you!
第一题
题目描述
- 给定一颗二叉树,二叉树每个节点都有唯一的正整数值代表节点,在遍历时,我们使用节点的数值作为标记。给定二叉树的前序和中序遍历结果,求二叉树的叶子节点个数。
输入
- 第一行,输入二叉树节点个数N,其中0 < N < 30000
- 第二行与第三行,分别输入二叉树的前序和中序遍历结果,每个节点对应唯一整数值
输出
- 二叉树叶子节点个数
样例输入
- 3
- 1 3 4
- 3 1 4
样例输出
- 2
分析
- 这是leetcode一个经典的题的拓展:给定一个二叉树的前序和中序遍历,让你重构一个二叉树。如果leetcod这个题会的话只需要简单加个统计就能解出字节这个题了。
- 大概的思路就是用递归的方法。利用这个关键信息:前序遍历的第一个节点一定是根节点root,而在中序遍历中root节点左侧的节点一定是它左子树的所有节点。
- 对于这个题的话,我们其实没必要去重构二叉树。当我们在重构的过程中发现root左侧的节点只有一个的时候,那么它左侧的这个节点一定是叶子节点。右侧的节点同理。
解法
#include <bits/stdc++.h>
using namespace std;
const int maxn = 30001;
int ans;
vector<int> pre(maxn, 0), mid(maxn, 0);
// 当前树的所有节点,在前序序列中的范围是[l, r],在中序序列中的范围是[ml, mr]
void dfs(int l, int r, int ml, int mr) {
if (l > r) return; // 当前树没节点了
if (l == r) {
// 如果这个树只有一个节点,那它肯定是叶子节点
ans++;
return;
}
int root = pre[l]; // 当前树的跟节点
int index;
for (int i = ml; i <= mr; ++i) {
// 在中序序列中找这个树的左子树范围和右子树范围
if (mid[i] == root) {
index = i;
break;
}
}
int lcnt = index - ml; // 左子树的节点数,利用中序序列中root节点左侧的是左子树,右侧的是右子树
int rcnt = mr - index; // 右子树的节点树
dfs(l + 1, l + lcnt, ml, index - 1); // 递归处理左子树,下同
dfs(l + lcnt + 1, r, index + 1, mr);
}
int main() {
int n;
while(cin >> n) {
for (int i = 1; i <= n; ++i) cin >> pre[i];
for (int i = 1; i <= n; ++i) cin >> mid[i];
ans = 0;
dfs(1, n, 1, n);
cout << ans << endl;
}
return 0;
}
n = int(input())
pre = input().split()
mid = input().split()
ans = 0
def dfs(l, r, ml, mr):
global ans
if l > r: return
if l == r:
ans += 1
return
root = pre[l]
index = ml
for i in range(ml, mr + 1):
if mid[i] == root:
index = i
break