AcWing 1497. 树的遍历(递归区间)java
🤠 原题地址

🤠 核心思路:
① 后序遍历序列的最后一个肯定是根节点,并且位于后边的节点肯定是 前边节点的 父节点或者兄弟节点
② 中序遍历序列的根节点左右两边的节点分别属于它的左子树和右子树
③ 前序遍历序列的第一个元素肯定是根节点,并且位于前边的节点肯定是 后边节点的 父节点或者兄弟节点
先从后序序列找出根节点,然后在中序序列(哈希表pos)找出左右子树,然后递归(build)处理左右子树,然后 bfs 宽搜 输出
import java.util.*;
public class 树的遍历
{
static int N = 30;
static int[] postorder = new int[N], inorder = new int[N];// 存后序遍历和中序遍历
// 错误初始化方式演示
// static HashMap<Integer, Integer> l, r, pos = new HashMap<>();
// 哈希表模拟二叉树(题目定义无重复元素)
//存 中序遍历 各节点对应的下标,方便通过后续遍历找出根节点,然后直接找出根节点所在中序遍历序列的位置
static HashMap<Integer, Integer> pos = new HashMap<>();
static HashMap<Integer, Integer> l = new HashMap<>();// l<根节点的值,左子树根节点的值>
static HashMap<Integer, Integer> r = new HashMap<>();// r<根节点的值,右子树根节点的值>
/**
* @param il 中序遍历区间左端点
* @param ir 中序遍历区间右端点
* @param pl 后序遍历区间左端点
* @param pr 后序遍历区间右端点
* @return
*/
static int build(int il, int ir, int pl, int pr)
{
int root = postorder[pr];// 后序遍历的最后一位肯定是根节点
int k = pos.get(root);// 获取根节点在中序遍历的下标
if (il < k)// 说明根 k 有左子树
{
// il ~ k-1 是 左子树的所有节点,长度为 len = (k-1-il)
// pl ~ pl+len: 是后序遍历序列里边左子树的范围
int lroot = build(il, k - 1, pl, pl + k - 1 - il);
l.put(root, lroot);// root 的左子树的根节点是 lroot
}
if (ir > k)// 根 k 有右子树
{
int rroot = build(k + 1, ir, pl + k - il, pr - 1);
r.put(root, rroot);// root 的右子树的根节点是 rroot
}
return root;
}
static void bfs(int root)
{
LinkedList<Integer> q = new LinkedList<Integer>();
q.add(root);
while (q.size() > 0)
{
Integer t = q.poll();
System.out.print(t + " ");
// 如果此节点有左子树,入队
if (l.containsKey(t))
q.add(l.get(t));
// 如果此节点有右子树,入队
if (r.containsKey(t))
q.add(r.get(t));
}
}
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
for (int i = 0; i < n; i++)
postorder[i] = sc.nextInt();
for (int i = 0; i < n; i++)
{
inorder[i] = sc.nextInt();
pos.put(inorder[i], i);// 记录中序遍历每个点的下标
}
int root = build(0, n - 1, 0, n - 1);
bfs(root);
}
}

浙公网安备 33010602011771号