2018届实习-阿里巴巴内推编程题,满二叉树的数组表示

对于一个由一位十进制整数构成的二叉树,如果深度不超过4,可以用一个三位十进制整数构成的数组表示,具体规则如下:

1、百位数表示树的层次L,1<=L<=4;十位数表示在该层次中的位置P,1<=P<=8;个位数表示数值V。

2、数组里,L一定是单增的,也就是说后一个数的L大于等于前一个数的L;

3、对于同一个L,P也是单增的,就是说在L不变的情况下,后一个数的P大于等于前一个数的P。

例如:[ 113, 215, 221 ]

      3

    /    \

 5       1

现在要求这个树所有到叶子节点的路径和,对于例子中,路径和为 (3+5)+(3+1)=12

题目的意思就是给出了几个三位数,比如 113 ,代表的是深度为1 ,左边第1个的数值 为 3 ; 215表示深度为2,左边第1个的数值为5 。解题思路就是将这个三位数数组转变为满二叉树数组,根据百位和十位推断出其数值 在满二叉树数组 的位置,然后递归求所有路径和。

百位(a)    十位(b)     数组中位置(index)

1                         1                      1

2                          1                     2

2                          2                     3

3                          1                     4

………..

可以推出公式: index  = pow(2,a-1)+b-1

结果为二叉树的数组表示

import java.util.ArrayList;
import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		// inputs为中间list,为了计算数组长度
		ArrayList<Integer> inputs = new ArrayList<Integer>();
		// 每行输入一个整数
		Scanner in = new Scanner(System.in);
		String line = in.nextLine();
		while (line != null && !line.isEmpty()) {
			int value = Integer.parseInt(line);
			if (value == 0)
				break;
			inputs.add(value);
			line = in.nextLine();
		}
		// 将list转化为数组
		int[] A = new int[inputs.size()];
		for (int i = 0; i < inputs.size(); i++) {
			A[i] = inputs.get(i).intValue();
		}
		int res = resolution(A);
		System.out.println(res);
	}

	/**
	 * 解析计算结果
	 * 
	 * @param 需要遍历的数组
	 * @return 结果
	 */
	public static int resolution(int[] A) {
		// tmp为一条路径的数字集合
		ArrayList<Integer> tmp = new ArrayList<Integer>();
		// t为存储所有路径结点的集合的集合。也可以用其他存储结构,如栈
		ArrayList<ArrayList<Integer>> t = new ArrayList<ArrayList<Integer>>();
		int nlen = A.length;
		int[] units = new int[nlen];// 个位数字集合
		int[] tens = new int[nlen];// 十位数字集合
		int[] hundreds = new int[nlen];// 百位数字集合
		for (int i = 0; i < nlen; i++) {
			hundreds[i] = A[i] / 100;
			tens[i] = A[i] / 10 % 10;
			units[i] = A[i] % 10;
		}
		// 因为深度最大为4,可以设总共结点为5的深度,结点个数为31(满二叉树结点个数),下标为0的结点不存储数值。
		int[] treeArray = new int[32];
		// 初值为Integer.MIN_VALUE,可以为任意负数,
		for (int i = 0; i < 32; i++) {
			treeArray[i] = Integer.MIN_VALUE;
		}
		// 存储实际的树节点值
		for (int i = 0; i < nlen; i++) {
			int loc = (int) Math.pow(2, tens[i] - 1) + units[i] - 1;
			treeArray[loc] = units[i];
		}
		findPath(treeArray, 1, t, tmp);
		// 结果集
		int r = 0;
		// 路径的个数。
		for (int i = 0; i < t.size(); i++) {
			// 每个路径的结点数
			for (int j = 0; j < t.get(i).size(); j++)
				r += t.get(i).get(j);
		}

		return r;
	}

	/**
	 * @param treeArray
	 *            需要排序的数组
	 * @param index
	 *            数组的下标,是从1 开始存储。
	 * @param res
	 *            结果数组的引用
	 * @param tmp
	 *            储存每条路径(从跟结点到叶子结点)的一条果集合
	 */
	public static void findPath(int[] treeArray, int index, ArrayList<ArrayList<Integer>> res, ArrayList<Integer> tmp) {
		// 加入跟结点
		if (treeArray[index] != Integer.MIN_VALUE)
			tmp.add(treeArray[index]);
		// 如果左右子树都是Integer.MIN_VALUE,说明为空,把之前存储的一条结果集合存储到res 中,并返回
		if (treeArray[2 * index] == Integer.MIN_VALUE && treeArray[2 * index + 1] == Integer.MIN_VALUE) {
			res.add(new ArrayList<Integer>(tmp));
			return;
		}
		// 遍历左子树,若左子树遍历完,则删除最后一个结点,则回溯到上一个结点(删除)。继续遍历右子树
		if (treeArray[2 * index] != Integer.MIN_VALUE) {
			findPath(treeArray, 2 * index, res, tmp);
			tmp.remove(tmp.size() - 1);

		}
		// 遍历右子树,若右子树遍历完,则删除最后一个结点,回溯到上一个结点。
		if (treeArray[2 * index + 1] != Integer.MIN_VALUE) {
			findPath(treeArray, 2 * index + 1, res, tmp);
			tmp.remove(tmp.size() - 1);
		}
	}
}
    原文作者:满二叉树
    原文地址: https://blog.csdn.net/mine_song/article/details/63262288
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞