层序序列+中序序列构建二叉树【Java实现】

题目描述

现有一棵n个结点的二叉树(结点编号为从0n-1),已知其层序序列和中序序列,求先序序列。

输入描述

第一行一个整数n(1≤n≤50),表示二叉树的结点个数;

第二行为n个整数,表示二叉树的层序序列;

第三行为n个整数,表示二叉树的中序序列。

输出描述

输出n个整数,表示二叉树的先序序列,中间用空格隔开,行末不允许有多余的空格。

样例

输入

6
0 2 5 1 4 3
1 2 4 0 5 3

输出

0 2 1 4 5 3
image-20230301200928546

思路分析

  1. 总体的思路和已知前序/后序+中序序列构建二叉树类似,将构建过程拆分为左子树,根部,右子树三个部分,难点在于如何将层序遍历的序列拆分为左,根,右三个部分

  2. 首先,层序遍历的第一个元素在当前子树中一定是根节点,由此完成了拆分根节点的目标

    其次,由于知道了根节点,因此我们可以通过根节点将左右子树进行划分,也就是说我们知道左子树和右子树具体都有哪些元素。

    因此,只需要利用哈希表leftMap<Integer,Boolean>将层序序列中左子树的部分标记为true即可,此时剩下未被标记的部分即为右子树,至此我们达成了将层序遍历序列划分为左,根,右三个部分的目标

  3. 接着便像前序+中序构建二叉树一样进行类似的处理就好,每次从层序序列中出队首元素作为根节点root,得到根节点在中序序列中的位置,将属于左子树的节点划分进队列leftTree,剩余划分进rightTree

  4. root的左子树即为中序序列中的左子树部分以及层序序列的左子树部分进行处理返回的结果,右子树同理

代码实现

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Scanner;

import javax.swing.text.AbstractDocument.LeafElement;

public class Main {
	static ArrayList<Integer> res = new ArrayList<Integer>();

	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		int n = scanner.nextInt();
		LinkedList<Integer> layerList = new LinkedList<Integer>();
		int midArr[] = new int[n];
		for (int i = 0; i < n; i++) {
			// 层序序列
			layerList.addLast(scanner.nextInt());
		}
		for (int i = 0; i < n; i++) {
			midArr[i] = scanner.nextInt();
		}
		TreeNode root = buildTreeByLayerAndMid(layerList, midArr, 0, n - 1);
		preOrder(root);
		for (int i = 0; i < n; i++) {
			System.out.print(res.get(i));
			if (i < n - 1) {
				System.out.print(" ");
			}
		}
	}

	public static TreeNode buildTreeByLayerAndMid(LinkedList<Integer> layerList, int midArr[], int left2, int right2) {
		if (layerList.isEmpty()) {
			return null;
		}
		// 当前节点若属于左子树则value为true
		HashMap<Integer, Boolean> leftMap = new HashMap<Integer, Boolean>();
		TreeNode root = new TreeNode(layerList.poll());
		int count = 0;
		for (int i = left2; i <= right2; i++) {
			// 找到了根节点
			if (midArr[i] == root.val) {
				break;
			}
			// 当前遍历到的部分属于左子树
			leftMap.put(midArr[i], true);
			count++;
		}
		LinkedList<Integer> leftTree = new LinkedList<Integer>();
		LinkedList<Integer> rightTree = new LinkedList<Integer>();
		for (Integer integer : layerList) {
			if (leftMap.getOrDefault(integer, false)) {
				leftTree.addLast(integer);
			} else {
				rightTree.addLast(integer);
			}
		}
		// left2+count指向根节点,因此-1后是左子树右边界
		root.left = buildTreeByLayerAndMid(leftTree, midArr, left2, left2 + count - 1);
		root.right = buildTreeByLayerAndMid(rightTree, midArr, left2 + count + 1, right2);
		return root;
	}

	public static void preOrder(TreeNode root) {
		if (root == null) {
			return;
		}
		res.add(root.val);
		preOrder(root.left);
		preOrder(root.right);

	}

}

class TreeNode {
	int val;
	TreeNode left;
	TreeNode right;

	public TreeNode(int val) {
		this.val = val;
	}

	public TreeNode() {
	}

}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值