zoukankan      html  css  js  c++  java
  • 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;
        }
    }
    View Code

    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:将两个链表存入栈或数组,逆序输出比较,直到找到第一个不相等的。
    View Code

    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;
            }
        }
    View Code

    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);
        }
    }
    View Code

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

    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);
        }
    }
    View Code

     
     
     
  • 相关阅读:
    读书笔记-《编写可读代码的艺术》一
    maven报错Error:(4, 35) java:程序包org.springframework.context不存在
    AutoCAD.Net/C#.Net QQ群:193522571 当需要把wipeout加入到block中时,必须把wipeout放在objectidcollection中的第一位
    AutoCAD.Net/C#.Net QQ群:193522571 绘制椭圆及椭圆弧
    AutoCAD.Net/C#.Net QQ群:193522571 Nested Select后,如果有上一级图元则ResultNestedContainer不为Null,从小到大,从父亲到爷爷
    AutoCAD.Net/C#.Net QQ群:193522571 标注对象Dimension中的DimensionText和Measurement的区别
    AutoCAD.Net/C#.Net QQ群:193522571 同一套窗体代码,同时用在Winform、PvBox和PvTools中
    AutoCAD.Net/C#.Net QQ群:193522571 当用户使用的不是默认的WCS坐标系时,打印程序容易打成空白,因为点没有转换
    AutoCAD.Net/C#.Net QQ群:193522571 ComBobox绑定Datatable并去除重复!
    AutoCAD.Net/C#.Net QQ群:193522571 字段包含于一个字符串的SQL
  • 原文地址:https://www.cnblogs.com/lingli-meng/p/7113369.html
Copyright © 2011-2022 走看看