树中两个节点的最低公共祖先(Java实现)

题目:求树中两个结点的最低公共祖先

分析:其实这是一组题目,考官没有说清楚树的结构,那么做法就不尽相同。

比如,如果是二叉搜索树的话,我们只需从根结点判断,如果二结点与根的左右子树比较一大一小,那么跟结点就是二者最低公共祖先;如果二结点都比左子结点小,向左子树递归进行比较;如果二结点都比右子树结点大,向右子树递归进行比较;

如果不是二叉搜索树,但带有指向父节点的指针,那么此题转换成在两个有相交的链表上求第一个相交点。

如果不带指向父节点的指针,那么我们可以记录从根结点到这两个结点的路径即可求出。


以下代码是:普通树(多个子树),子树没有指向父节点的指针

package go.jacob.day520;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import javax.management.RuntimeErrorException;

public class Demo1 {
	public static void main(String[] args) {
		test01();
        System.out.println("==========");
        test02();
        System.out.println("==========");
        test03();
	}
	
	// 形状普通的树
    //             1
    //           /   \
    //         2      3
    //        /         \
    //      4            5
    //     / \        /  |  \
    //    6   7      8   9  10
    public static void test01() {
        TreeNode n1 = new TreeNode(1);
        TreeNode n2 = new TreeNode(2);
        TreeNode n3 = new TreeNode(3);
        TreeNode n4 = new TreeNode(4);
        TreeNode n5 = new TreeNode(5);
        TreeNode n6 = new TreeNode(6);
        TreeNode n7 = new TreeNode(7);
        TreeNode n8 = new TreeNode(8);
        TreeNode n9 = new TreeNode(9);
        TreeNode n10 = new TreeNode(10);

        n1.children.add(n2);
        n1.children.add(n3);

        n2.children.add(n4);

        n4.children.add(n6);
        n4.children.add(n7);

        n3.children.add(n5);

        n5.children.add(n8);
        n5.children.add(n9);
        n5.children.add(n10);

        System.out.println(getLastCommonParent(n1, n9, n10));
    }

    // 树退化成一个链表
    //               1
    //              /
    //             2
    //            /
    //           3
    //          /
    //         4
    //        /
    //       5
    private static void test02() {
        TreeNode n1 = new TreeNode(1);
        TreeNode n2 = new TreeNode(2);
        TreeNode n3 = new TreeNode(3);
        TreeNode n4 = new TreeNode(4);
        TreeNode n5 = new TreeNode(5);

        n1.children.add(n2);
        n2.children.add(n3);
        n3.children.add(n4);
        n4.children.add(n5);

        System.out.println(getLastCommonParent(n1, n4, n5));
    }

    // 树退化成一个链表,一个结点不在树中
    //               1
    //              /
    //             2
    //            /
    //           3
    //          /
    //         4
    //        /
    //       5
    private static void test03() {
        TreeNode n1 = new TreeNode(1);
        TreeNode n2 = new TreeNode(2);
        TreeNode n3 = new TreeNode(3);
        TreeNode n4 = new TreeNode(4);
        TreeNode n5 = new TreeNode(5);
        TreeNode n6 = new TreeNode(6);

        n1.children.add(n2);
        n2.children.add(n3);
        n3.children.add(n4);
        n4.children.add(n5);

        System.out.println(getLastCommonParent(n1, n5, n6));
    }

	
	
	
	/*
	 * 获取两个节点的最低公共祖先
	 */
	public static TreeNode getLastCommonParent(TreeNode root, TreeNode p1, TreeNode p2) {
		//path1和path2分别存储根节点到p1和p2的路径(不包括p1和p2)
		List<TreeNode> path1 = new ArrayList<TreeNode>();
		List<TreeNode> path2 = new ArrayList<TreeNode>();
		List<TreeNode> tmpList = new ArrayList<TreeNode>();

		getNodePath(root, p1, tmpList, path1);
		getNodePath(root, p2, tmpList, path2);
		//如果路径不存在,返回空
		if (path1.size() == 0 || path2.size() == 0)
			return null;

		return getLastCommonParent(path1, path2);
	}

	// 获取根节点到目标节点的路径
	public static void getNodePath(TreeNode root, TreeNode target, List<TreeNode> tmpList, List<TreeNode> path) {
		//鲁棒性
		if (root == null || root == target)
			return;
		tmpList.add(root);
		List<TreeNode> children = root.children;
		for (TreeNode node : children) {
			if (node == target) {
				path.addAll(tmpList);
				break;
			}
			getNodePath(node, target, tmpList, path);
		}

		tmpList.remove(tmpList.size() - 1);
	}
	//将问题转化为求链表最后一个共同节点
	private static TreeNode getLastCommonParent(List<TreeNode> p1, List<TreeNode> p2) {
		TreeNode tmpNode = null;
		for (int i = 0; i < p1.size(); i++) {
			if (p1.get(i) != p2.get(i))
				break;
			tmpNode = p1.get(i);
		}

		return tmpNode;
	}

	// 节点类
	private static class TreeNode {
		int val;

		List<TreeNode> children = new ArrayList<>();


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

		@Override
		public String toString() {
			return val + "";
		}
	}
}

点击打开链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值