美文网首页
剑指offer | 树中两个结点的最低公共祖先

剑指offer | 树中两个结点的最低公共祖先

作者: icebreakeros | 来源:发表于2019-08-01 09:36 被阅读0次

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

    树是二叉搜索树

    分析:
    二叉搜索树都是排序过的,位于左子树的结点都比父结点小,而位于右子树的结点都比父结点大
    从根结点开始和两个输入的结点进行比较,如果当前结点的值比两个结点的值都大,那么最低公共父结点一定是在当前结点的左子树中,于是下一步遍历当前结点的左子结点
    如果当前结点的值比两个结点的值都小,那么最低公共结点一定是在当前结点的右子树中,于是下一步遍历当前结点的右子结点
    这样在树中从上到下找到第一个在两个输入结点的值之间的结点,就是最低公共祖先

    树不是二叉树但是有指向父结点的指针

    分析:
    如果树中每个节点都有指向父结点的指针,这个问题可以转换为求两个链表的第一个公共结点

    树是一棵普通的树

    分析:
    从根结点开始遍历一棵树,每遍历到一个结点,判断两个输入结点是不是在它的子树中
    如果在子树中,则分别遍历它的所有子结点,并判断两个输入结点是不是在它们子树中
    这样从上到下一直找到的第一个结点,它自己的子树中同时包含两个输入的结点而它的子结点却没有,那么该结点就是最低公共祖先

    优化:
    两个链表保存从根节点到输入的两个结点的路径,然后把问题转换成两个链表的最后公共结点

    class Node<Key extends Comparable<Key>, Vaule> {
        public Key key;
        public Vaule vaule;
        public Node left, right;
    
        public Node(Key key, Vaule vaule) {
            this.key = key;
            this.vaule = vaule;
        }
    }
    
    public class LastCommonParent {
    
        // 获取结点k的路径
        private boolean getNodePath(Node root, Node k, List<Node> path) {
            if (root.key.compareTo(k.key) == 0) {
                return true;
            }
    
            path.add(root);
            boolean found = false;
            if (!found && Optional.ofNullable(root.left).isPresent()) {
                found = getNodePath(root.left, k, path);
            }
            if (!found && Optional.ofNullable(root.right).isPresent()) {
                found = getNodePath(root.right, k, path);
            }
            if (!found) {
                path.remove(path.size() - 1);
            }
            return found;
        }
    
        // 公共子结点
        private Node getLastCommonNode(List<Node> m, List<Node> n) {
            if (Optional.ofNullable(m).isEmpty() || 
                    Optional.ofNullable(n).isEmpty()) {
                throw new RuntimeException("list empty");
            }
    
            Node result = null;
            int count = 0;
            while (count < m.size() && count < n.size()) {
                if (m.get(count).key.compareTo(n.get(count).key) == 0) {
                    result = m.get(count);
                }
                count++;
            }
            return result;
        }
    
        // true表示结点参数正确
        private boolean checkNode(Node... nodes) {
            boolean flag = true;
            for (Node node : nodes) {
                if (Optional.ofNullable(node).isEmpty()) {
                    flag = false;
                }
            }
            return flag;
        }
    
        public Node getLastCommonParent(Node root, Node m, Node n) {
            if (!checkNode(root, m, n)) {
                throw new RuntimeException("node empty");
            }
    
            List<Node> ml = new LinkedList<>();
            List<Node> nl = new LinkedList<>();
            if (!getNodePath(root, m, ml) || !getNodePath(root, n, nl)) {
                throw new RuntimeException("invalid parameters");
            }
    
            return getLastCommonNode(ml, nl);
        }
    }
    

    相关文章

      网友评论

          本文标题:剑指offer | 树中两个结点的最低公共祖先

          本文链接:https://www.haomeiwen.com/subject/zpbfdctx.html