236_二叉树的最近公共祖先

236_二叉树的最近公共祖先

 

package 二叉树.BT;

import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;

/**
 * https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/
 * @author Huangyujun
 *
 */
public class _236_二叉树的最近公共祖先 {
    
    /**
     * 方法1:存父节点的方式【因为使用了map 字典,存储父结点导致效率不高】
     * @author Huangyujun
     * 思路:parent:【键:当前结点的值;  值:父结点】
     *
     */
    class Solution {
        Map<Integer, TreeNode> parent = new HashMap<Integer, TreeNode>();
        Set<Integer> visited = new HashSet<Integer>();

        public void dfs(TreeNode root) {
            if (root.left != null) {
                parent.put(root.left.val, root);
                dfs(root.left);
            }
            if (root.right != null) {
                parent.put(root.right.val, root);
                dfs(root.right);
            }
        }

        public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
            dfs(root);
            while (p != null) {
                visited.add(p.val);
                p = parent.get(p.val);
            }
            while (q != null) {
                if (visited.contains(q.val)) {
                    return q;
                }
                q = parent.get(q.val);
            }
            return null;
        }
    }
    
    
    /**
     * 我的思路跟官网差不多,但是因为我少了父节点存储后的遍历,导致后边比较bug不断
     */
    Deque<TreeNode> p_stack = new LinkedList<>();
    Deque<TreeNode> q_stack = new LinkedList<>();
    TreeNode p;
    TreeNode q;
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        this.p = p;
        this.q = q;
        dfs1(root);
        dfs2(root);
        while(!p_stack.isEmpty() && !q_stack.isEmpty()) {
            if(p_stack.peekLast().val == q_stack.peekLast().val) {
                return p_stack.peekLast();
            }
            p_stack.pollLast(); 
            q_stack.pollLast();      
        }
        return null;
    }
    //问题出现在传入一个存储结点的栈,发生了递归,。。。。原因2:出现在比较结点长度不一致时,不是同步比较呀【舒服的方式时官网的方式】
    private void dfs1(TreeNode root) {
        if(root == null)    return;
        //前序遍历
        if(root.val == p.val) {
            return;
        }else {
            p_stack.push(root);
        }
        dfs1(root.left);
        dfs1(root.right);
    }
    private void dfs2(TreeNode root) {
        if(root == null)    return;
        //前序遍历
        if(root.val == q.val) {
            return;
        }else {
            q_stack.push(root);
        }
        dfs2(root.left);
        dfs2(root.right);
    }
    
    /**
     * 方式2:递归
     * @author Huangyujun
     *
    ○ 树形一:root为p,q中的一个,这时公共祖先为root
    ○ 树形二:p,q分别在root的左右子树上(p在左子树,q在右子树;还是p在右子树,q在左子树的情况都统一放在一起考虑)这时满足p,q的最近公共祖先的结点也只有root本身
    ○ 树形三:p和q同时在root的左子树;或者p,q同时在root的右子树,这时确定最近公共祖先需要遍历子树来进行递归求解。
     */
    class Solution2 {
        public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
            if (root==p||root==q) {    //树形一:root为p,q中的一个,这时公共祖先为root
                return root;
            }
            if (root!=null){//否则,root 不是p、q 中其中的一个 【需要在两个子树中找到最近祖父】
                TreeNode lNode=lowestCommonAncestor(root.left,p,q);
                TreeNode rNode=lowestCommonAncestor(root.right,p,q);
                if (lNode!=null&&rNode!=null) {//树形二:p,q分别在root的左右子树上
                     return root;
                }else if(lNode==null) {//树形三:p和q同时在root的右子树
                    return rNode;
                }
                else { //树形三:p和q同时在root的左子树
                    return lNode;
                }
            }
            return null;
        }
    }


}

 

posted @ 2021-12-20 00:11  一乐乐  阅读(32)  评论(0编辑  收藏  举报