Call Numbers-先根序列和中根序列判断是否可以组成一个树

题目:

当前存在各节点最多含有2个子节点的树。树中有N个节点,每个节点在1到 N为止的自然数中获得唯一值。现在需要按照如下两种方法,通过一行输出节点的号码。

 

方法 1: 优先输出root的号码。然后在root的左边和右边中选择一个子树,输出这个子树的号码。然后输出相对的另一个子树的号码。输出子树里面号码的方法跟root的方法相同,需要不断反复。注意的是,每个节点上先选左边的子树还是先选右边的子树是可以随意的。

 

方法 2: 在root的左边和右边中选择一个子树,输出这个子树的号码。然后输出root的号码。再输出相对的另一个子树的号码。输出子树里面号码的方法跟root的方法相同,需要不断反复。注意的是,每个节点上先选左边的子树还是先选右边的子树是可以随意的。

 

 

在如下图片的树中,按照方法 1可以输出“4, 1, 5, 6, 2, 8, 3, 7”, “4, 8, 7, 3, 1, 5, 6, 2” 等。还有,按照方法2可以输出“6, 5, 2, 1, 4, 7, 8, 3”, “1, 6, 5, 2, 4, 3, 8, 7” 等。

 

 

请接收通过方法1和方法2输出的内容,编写这两个输出是否能在相同的树中做成的判断程序。

 

[输入

Input文件的第一行给出文件上包含的测试用例个数。各测试用例的第一行给出树的节点个数N(1 ≤ N ≤ 100,000)。 然后下一行给出通过方法1输出的N个数。再下一行给出通过方法2输出的N个数。

 

[输出] 

各测试用例的答案按照顺序标准输出,每个测试用例的开始输出“#x”。这时,x是测试用例号码。在同一行上隔一个空格后,当两个输出可以在相同的树中做成时,去掉引号输出“POSSIBLE”, 绝对不能在相同的树中做成时,去掉引号输出 “IMPOSSIBLE”。

 

[输入输出 案例]

(输入)

2

8

4 1 5 6 2 8 3 7

6 5 2 1 4 7 8 3

4

1 2 3 4

3 1 4 2

 

(输出)

#1 POSSIBLE

#2 IMPOSSIBLE


题目给出 两个 二叉树的遍历序列,姑且称之为 先根遍历 序列 中根遍历序列

针对这个题目:
要判断两个遍历序列是否可能 属于同一棵树
思路是:将两个序列,向下找出所有子树,一一比对


package Professional;

import java.io.BufferedReader;
//import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
import java.util.Stack;

public class CallNumbers {
	static int T, N;
	static boolean answer;
	static int[] arrMid = new int[100001];
	static int[] arrPre = new int[100001];
	static int[] arrPPos = new int[100001];

	static boolean found;

	public static void main(String args[]) throws Exception {
//		long start = System.currentTimeMillis();
		StringTokenizer st;

//		System.setIn(new FileInputStream(
//				"D:/AndroidProject/workspace/javatest-20150828/CallNumbers.txt"));

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		T = Integer.parseInt(br.readLine());
		for (int test_case = 1; test_case <= T; test_case++) {
			N = Integer.parseInt(br.readLine());

			st = new StringTokenizer(br.readLine());
			for (int i = 1; i <= N; i++) {
				arrMid[i] = Integer.parseInt(st.nextToken());
			}

			st = new StringTokenizer(br.readLine());
			for (int i = 1; i <= N; i++) {
				arrPre[i] = Integer.parseInt(st.nextToken());
				arrPPos[arrPre[i]] = i;
			}

			answer = true;
			check(1, N, 1, N);

			if (answer)
				System.out.println("#" + test_case + " " + "POSSIBLE");
			else
				System.out.println("#" + test_case + " " + "IMPOSSIBLE");

			Arrays.fill(arrMid, 0);
			Arrays.fill(arrPre, 0);
			Arrays.fill(arrPPos, 0);
		}
//		System.out.println("Time:" + (System.currentTimeMillis() - start));
	}

	public static void check(int ms, int me, int ps, int pe) {
		Stack<Integer> stack = new Stack<Integer>();
		int mroot, proot, pson;
		int pls, ple, prs, pre;
		int mls, mle, mrs, mre;

		stack.add(ms);
		stack.add(me);
		stack.add(ps);
		stack.add(pe);
		while (!stack.isEmpty()) {
			pre = stack.pop();
			pls = stack.pop();
			mre = stack.pop();
			mroot = stack.pop();

			if (mre == mroot) {
				if (!(arrMid[mroot] == arrPre[pls])) {
					answer = false;
					return;
				}
			} else {
				proot = arrPPos[arrMid[mroot]];
				ple = proot - 1;
				prs = proot + 1;
				mls = mroot + 1;

				if (proot == pls) {
					stack.add(mls);
					stack.add(mre);
					stack.add(prs);
					stack.add(pre);
				} else if (proot == pre) {
					stack.add(mls);
					stack.add(mre);
					stack.add(pls);
					stack.add(ple);
				} else if (proot > pls && proot < pre) {
					pson = arrPPos[arrMid[mls]];
					if (pson >= pls && pson <= ple) {
						mle = mls + (ple - pls);
						mrs = mle + 1;

						stack.add(mls);
						stack.add(mle);
						stack.add(pls);
						stack.add(ple);

						stack.add(mrs);
						stack.add(mre);
						stack.add(prs);
						stack.add(pre);
					} else if (pson >= prs && pson <= pre) {
						mle = mls + (pre - prs);
						mrs = mle + 1;

						stack.add(mls);
						stack.add(mle);
						stack.add(prs);
						stack.add(pre);

						stack.add(mrs);
						stack.add(mre);
						stack.add(pls);
						stack.add(ple);
					} else {
						answer = false;
						return;
					}
				} else {
					answer = false;
					return;
				}
			}
		}
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值