50、树中两个节点的公共祖先

详细的询问:

1、该树是二叉查找树? 最近公共祖先----二叉查找树:(http://www.lintcode.com/problem/lowest-common-ancestor/)

思路:利用左子树特点:左子树 < 根 <= 右,输入节点跟根节点比较,都小于,在左子树,都大约右子树,递归的去遍历;找到当前节点在两个输入大小之间,当前节点就是。

递归和非递归

public class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (root == null) {
            return null;
        }
        if (root.val > Math.max(p.val, q.val)) {
            return lowestCommonAncestor(root.left, p, q);
        } else if (root.val < Math.min(p.val, q.val)) {
            return lowestCommonAncestor(root.right, p, q);
        } else{
            return root;
        }
    }
}
非递归:
public class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        while(true){
            if (root.val > Math.max(p.val, q.val)){
                root = root.left;
            } else if (root.val < Math.min(p.val, q.val)){
                root = root.right;
            }
            else{
                break;
            }
        }
        return root;
    }
}

2、该树有指向父节点的指针

最近公共祖先----普通的树有指向父节点的指针:

思路:转换为求两个链表的第一个公共节点。从叶子节点到根节点都是由一个pparent连起来的链表。

对齐或栈

方法1:计算两个链表长度,len = 长度之差,对齐链表,然后依次遍历比较
/**
 * Definition of ParentTreeNode:
 *
 * class ParentTreeNode {
 *     public ParentTreeNode parent, left, right;
 * }
 */
public class Solution {
    /**
     * @param root: The root of the tree
     * @param A, B: Two node in the tree
     * @return: The lowest common ancestor of A and B
     */
    public ParentTreeNode lowestCommonAncestorII(ParentTreeNode root,
                                                 ParentTreeNode A,
                                                 ParentTreeNode B) {

        int a_L = getL(A);
        int b_L = getL(B);
        int diff = a_L - b_L;
        ParentTreeNode l = A;
        ParentTreeNode s = B;
        if(diff < 0){
            l = B;
            s = A;
            diff = b_L - a_L;
        }
        while(diff > 0) {
            l = l.parent;
            diff--;
        }
        while(l != null && s != null && l != s) {
            l = l.parent;
            s = s.parent;
        }

        return l;
    }
    public int getL(ParentTreeNode node){
        int len = 0;
        ParentTreeNode pnode = node;
        while(pnode != null) {
            pnode = pnode.parent;
            len++;
        }
        return len;
    }
}
方法2:将两个链表存入栈或数组,逆序输出比较,直到找到第一个不相等的。

3、最近公共祖先----普通树,没有指针()

1)ab在树里,后序遍历,递归

public static TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (root == null) return null;

        if (root == p || root == q) return root;

        // Post order traveral
        TreeNode l = lowestCommonAncestor(root.left, p, q);
        TreeNode r = lowestCommonAncestor(root.right, p, q);

        if (l != null && r != null) {
            return root;
        } else {
            return l != null ? l : r;
        }
    }

2)可能不在树里

思路: 在二叉树中来搜索p和q,然后从路径中找到最后一个相同的节点即为父节点,我们可以用递归来实现.后序遍历二叉树,得到从根节点到目标节点的“路径”。

方法一、

  1)判断改点在不在子树中covers()

  2)公共祖先helper()分同边,异边

改方法每次都会重复访问在不在子树,

public class Solution {

    public TreeNode lowestCommonAncestor3(TreeNode root, TreeNode A, TreeNode B) {
       if(!covers(root,A) || !covers(root,B)){
           return null;
       }
       return Helper(root, A, B);
    }

    //判断该节点node是否在当前节点root的子树里
    public boolean covers(TreeNode root, TreeNode node){
        if(root == null) {
            return false;
        }
        if(root == node){
            return true;//当前节点即为node
        }
        return covers(root.left, node) || covers(root.right, node);//节点在当前节点的左右子树里
    }
    //找公共节点
    public TreeNode Helper(TreeNode root, TreeNode A, TreeNode B) {
         // write your code here
        if(root == null) {
            return null;
        }
        if (root == A || root == B){
            return root;
        }
        boolean a_i_L = covers(root.left, A);
        boolean b_i_L = covers(root.left, B);
        //不在同一边
        if(a_i_L != b_i_L){
            return root;
        }
        //在通一边
        TreeNode child_side = b_i_L ?root.left : root.right;
        return Helper(child_side, A, B);
    }
}

方法二:构造一个结构类,两种方法。

class ResultType {
    public boolean a_exist, b_exist;
    public TreeNode node;
    ResultType(boolean a, boolean b, TreeNode n) {
        a_exist = a;
        b_exist = b;
        node = n;
    }
}

public class Solution {
    public TreeNode lowestCommonAncestor3(TreeNode root, TreeNode A, TreeNode B) {
        // write your code here
        ResultType rt = helper(root, A, B);
        if (rt.a_exist && rt.b_exist)
            return rt.node;
        else
            return null;
    }

    public ResultType helper(TreeNode root, TreeNode A, TreeNode B) {
        if (root == null)
            return new ResultType(false, false, null);

        ResultType left_rt = helper(root.left, A, B);
        ResultType right_rt = helper(root.right, A, B);

        boolean a_exist = left_rt.a_exist || right_rt.a_exist || root == A;
        boolean b_exist = left_rt.b_exist || right_rt.b_exist || root == B;

        if (root == A || root == B)
            return new ResultType(a_exist, b_exist, root);

        if (left_rt.node != null && right_rt.node != null)
            return new ResultType(a_exist, b_exist, root);
        if (left_rt.node != null)
            return new ResultType(a_exist, b_exist, left_rt.node);
        if (right_rt.node != null)
            return new ResultType(a_exist, b_exist, right_rt.node);

        return new ResultType(a_exist, b_exist, null);
    }
}

时间: 2024-10-06 07:59:36

50、树中两个节点的公共祖先的相关文章

二棵树某两个节点的公共祖先。

1. 如果是有parent指针的树,可以转化成 求两个链表第一个公共节点的问题. 对于无parent指针普通二叉树(假定这两个节点一定在树中,否则需要先遍历一边树查找是否存在该节点) 1. (剑指offer的解法),先用一定的空间记录从根节点到两个节点各自的路径,然后找这两个路径最后一个相交的节点. 2.  CC150,递归求解. TreeNode commonAncestor(TreeNode root, TreeNode p, TreeNode q){ } 二棵树某两个节点的公共祖先.,布布

求树中两个节点的最低公共祖先

情形1:树是搜索二叉树 思路:从树的根节点开始遍历,如果根节点的值大于其中一个节点,小于另外一个节点,则根节点就是最低公共祖先.否则如果根节点的值小于两个节点的值,则递归求根节点的右子树,如果大于两个节点的值则递归求根的左子树.如果根节点正好是其中的一个节点,那么说明这两个节点在一条路径上,所以最低公共祖先则是根节点的父节点 public static BinaryTreeNode getLowestCommonAncestor(BinaryTreeNode rootParent,BinaryT

树中两个节点的最低公共祖先

树是二叉查找树的情况 题目来自LeetCode:https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/ Lowest Common Ancestor of a Binary Search Tree Total Accepted: 3402 Total Submissions: 8709 My Submissions Question Solution Given a binary search t

二叉树求两节点最低公共祖先,求随意两节点距离

-------1.求最低公共祖先LCA( Lowest Common Ancestor ) 什么是最低公共祖先?例如以下图.2与3的LCA是1:1与4的LCA是1:4与5的LCA是2. 那么给定两个节点n1和n2,如今要找出它们的LCA,怎样找?首先分析一下,n1和n2有几种情况?第一种.n1和n2分别在一个节点的左右子树中,比方4和5,LCA就是2,5和6,LCA就是1.2和3,LCA就是1:另外一种.n1和n2都在左子树或右子树,比方2和4,LCA就是2,1和4.LCA就是1. 一共这两种情

LeetCode Recover Binary Search Tree——二查搜索树中两个节点错误

Two elements of a binary search tree (BST) are swapped by mistake.Recover the tree without changing its structure.Note:A solution using O(n) space is pretty straight forward. Could you devise a constant space solution?二叉排序树中有两个节点被交换了,要求把树恢复成二叉排序树.最简单

[程序员代码面试指南]二叉树问题-找到二叉树中两节点最近公共祖先

题解 法一:后序遍历.搞清返回值逻辑. todo 更新别的方法 法一代码 public class Parent { public static void main(String args[]) { Node n1=new Node(1); Node n2=new Node(2); Node n3=new Node(3); Node n4=new Node(4); n1.left=n2; n1.right=n3; n3.left=n4; System.out.print(firstParent(

二叉搜索树中两个节点的旋转

struct TreeNode { //... PTreeNode& Child (Direction dir) { return dir == left? leftChild : rightChild; } }; class BST { private: // ... void Routate (PTreeNode, Direction); public: // ... void LeftRoutate (PTreeNode); void RightRoutate (PTreeNode); }

树中两个结点的最低公共祖先

情况1: 树为二叉排序树. 思路:从根结点开始和输入的两个结点进行比较,如果当前结点的值比两个结点的值都大,那么最低的祖先肯定在左子树中,于是下一步遍历当前结点的左子结点.如果当前结点的值比两个结点的值都小,那么最低的祖先肯定在右子树种,于是下一步遍历当前结点的右子结点.如果当前结点正好是输入的两个结点之一,说明这两个结点有一个是另一个的祖先,这时输出当前结点的父节点即可. /* 二叉树的公共祖先系列 1.二叉树为二叉排序树 by Rowandjj 2014/8/20 */ #include<i

lca(最近公共祖先(在线)) 倍增法详解

转自大佬博客 : https://blog.csdn.net/lw277232240/article/details/72870644 描述:倍增法用于很多算法当中,通过字面意思来理解 LCA是啥呢  在一棵树当中 lca表示的是两个节点最近公共祖先, 大家看这课树哈节点5 ,3的lca就是1,13和11的LCA就是6.节点8,12的lca就是8,那么我们如何通过被增来实现LCA呢. 首先请大家认真看下面的分析. depth[x],表示x节点的深度. 大家看下这个数组 grand[x][i] ,