zoukankan      html  css  js  c++  java
  • leetcode面试准备:Lowest Common Ancestor of a Binary Search Tree & Binary Tree

    leetcode面试准备:Lowest Common Ancestor of a Binary Search Tree & Binary Tree

    1 题目

    Binary Search Tree的LCA

    Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BST.
    According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes v and w as the lowest node in T that has both v and w as descendants (where we allow a node to be a descendant of itself).”

            _______6______
           /              
        ___2__          ___8__
       /              /      
       0      _4       7       9
             /  
             3   5
    

    For example, the lowest common ancestor (LCA) of nodes 2 and 8 is 6. Another example is LCA of nodes 2 and 4 is 2, since a node can be a descendant of itself according to the LCA definition.

    接口: TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q)

    Binary Tree的LCA

    Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree.
    According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes v and w as the lowest node in T that has both v and w as descendants (where we allow a node to be a descendant of itself).”

            _______3______
           /              
        ___5__          ___1__
       /              /      
       6      _2       0       8
             /  
             7   4
    

    For example, the lowest common ancestor (LCA) of nodes 5 and 1 is 3. Another example is LCA of nodes 5 and 4 is 5, since a node can be a descendant of itself according to the LCA definition.

    接口: TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q)

    2 思路

    在二叉树数中寻找两个节点的最低公共父节点。更容易一点的题目是限定在搜索二叉树中。
    搜索二叉树:左子树 < root < 右子树,即中序遍历有序。

    思路1

    遍历2次,找到节点pq的路径,然后在遍历1次两条路径,找到公共的最低节点。这个节点是所求的。

    • 搜索二叉树:利用BST性质,判断节点值的大小,很容易找到节点的路径。
    • 一般二叉树:DFS找公共节点

    复杂度: 遍历3次,用了额外的储存空间。如何分析树的时间和空间复杂度?

    思路2

    树的结构,很容易想到递归。LCA要么在root上,要么在左右子树中。

    • 搜索二叉树
      根据BST的性质,两个节点p,q的公共袓先root, 一定满足p <= root <= q 或者 p >= root >= q。
      使用递归可以轻松解决此问题。分为三种情况讨论:
    1. P, Q都比root小,则LCA在左树,我们继续在左树中寻找LCA
    2. P, Q都比root大,则LCA在右树,我们继续在右树中寻找LCA
    3. 其它情况,表示P,Q在root两边,或者二者其一是root,或者都是root,这些情况表示root就是LCA,直接返回root即可。
    • 一般二叉树
      The idea is to traverse the tree starting from root. 具体见代码实现吧。
    1. If any of the given keys (n1 and n2) matches with root, then root is LCA (assuming that both keys are present).
    2. If root doesn’t match with any of the keys, we recur for left and right subtree. The node which has one key present in its left subtree and the other key present in right subtree is the LCA.
    3. If both keys lie in left subtree, then left subtree has LCA also, otherwise LCA lies in right subtree.

    3 代码

    BST的LCA

    只写了思路2的代码

    	// 递归
    	public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
    		if (root == null)
    			return root;
    		final int value = root.val;
    		if (Math.max(p.val, q.val) < value)
    			return lowestCommonAncestor(root.left, p, q);
    		if (Math.min(p.val, q.val) > value)
    			return lowestCommonAncestor(root.right, p, q);
    		return root;
    	}
    
    	// 迭代做法
    	public TreeNode lca(TreeNode root, TreeNode p, TreeNode q) {
    		TreeNode cur = root;
    		for (;;) {
    			int value = cur.val;
    			if (p.val < value && q.val < value)
    				cur = cur.left;
    			else if (p.val > value && q.val > value)
    				cur = cur.right;
    			else
    				return cur;
    		}
    	}
    

    BT的LCA

    思路2的代码

    	public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
    		if (root == null) {
    			return null;
    		}
    
    		// If the root is one of a or b, then it is the LCA
    		if (root == p || root == q) {
    			return root;
    		}
    
    		TreeNode left = lowestCommonAncestor(root.left, p, q);
    		TreeNode right = lowestCommonAncestor(root.right, p, q);
    
    		// If both nodes lie in left or right then their LCA is in left or right,
    		// Otherwise root is their LCA
    		if (left != null && right != null) {
    			return root;
    		}
    
    		return (left != null) ? left : right;
    	}
    
    

    思路1的代码

    	public TreeNode lca(TreeNode root, TreeNode p, TreeNode q) {
    		Deque<TreeNode> pPath = new LinkedList<TreeNode>();
    		Deque<TreeNode> qPath = new LinkedList<TreeNode>();
    		findPath(root, p, pPath);
    		findPath(root, q, qPath);
    		
    		TreeNode prev = null;
    		for (; !pPath.isEmpty() && !qPath.isEmpty();) {
    			TreeNode parent = pPath.removeFirst();
    			if (parent == qPath.removeFirst()) {
    				prev = parent;
    			} else {
    				break;
    			}
    		}
    		return prev;
    	}
    	
    	/**
    	 * DFS 寻找路径
    	 */
    	private boolean findPath(TreeNode root, TreeNode node, Deque<TreeNode> path) {
    		if (root == null)
    			return false;
    		if (root == node) {
    			path.addLast(root);
    			return true;
    		}
    		path.addLast(root);
    		if (findPath(root.left, node, path))
    			return true;
    		if (findPath(root.right, node, path))
    			return true;
    		path.removeLast();
    		return false;
    	}
    

    4 总结

    树的题目,不熟悉,多总结一下吧。

    5 参考

  • 相关阅读:
    python深浅拷贝
    软件开发目录规范
    编码规范
    python进程、线程、协程的介绍及使用
    soket粘包问题及解决方案
    python socket通信
    数据开发_机器学习
    数据开发_开发工具以及工具链
    数据开发_Python读取文件
    数据开发_Java设计模式_IO以及读取资源文件
  • 原文地址:https://www.cnblogs.com/byrhuangqiang/p/4710851.html
Copyright © 2011-2022 走看看