码迷,mamicode.com
首页 > 其他好文 > 详细

Lowest Common Ancestor of a Binary Tree题解

时间:2015-11-22 16:02:36      阅读:131      评论:0      收藏:0      [点我收藏+]

标签:

这是LeetCode上的一道题,让我们先来看一看题目:

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.

简而言之就是已知二叉树,已知二叉树中的两个节点,求这两个节点最近的公共祖先。

同时在代码部分,题目给出了所要求的数据结构,我们可以注意到这一数据结构中,我们只能直接找到这一个节点的左右孩子,但是并不能直接找到他的双亲。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */

  

基于这样的数据结构,对于没有学过算法或者学过一些算法不过比较渣的同学(比如我。。。),可能的第一反应就是从根节点开始逐层向下遍历,判断每一个节点是否是所求的公共祖先,然后再找到这些符合条件的节点中最低层的,这种方法显然是十分低效的,因为以每一个节点为根节点的子树都被遍历了很多很多遍。于是为了优化这种算法,我们很自然地想到能否通过调用递归函数来储存中间信息,只对树进行一次遍历解决这个问题。使用这种方法时我们首先需要考虑两个问题:树的遍历方法是先根遍历中根遍历还是什么别的?递归函数的返回值应该储存什么信息?

为了解决这两个问题,我们回归到最近共同祖先这个概念本身。若所求节点是已知节点的最近共同祖先,则说明两点,首先这个节点一定是已知节点的共同祖先,同时这个节点的所有后代(例如左孩子,右孩子)都不是已知节点的共同祖先。因此我们可以总结出该问题的两种不同情况,第一种情况是p,q两个节点分别在所求节点的左子树,右子树中;第二种情况是所求节点本身就是p或q节点。

应对第一种情况,我们发现递归函数的返回值需要能够反映一个节点是否是p或q节点的祖先即可,若一个节点的左右孩子都是p或q节点的祖先,则该节点就是p和q的最近共同祖先。同时我们还需要先对根节点进行特判,判断其是否就是p或q节点,则这时不用再遍历该节点的子树了。经过这些分析,我们决定采取先根遍历的形式,先判断某节点是否是p或q节点,至于递归函数的返回值,如果某节点是p或q的祖先,返回该节点指针,否则返回NULL。

实现这种思路的代码如下:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
                if(!root) 
			return NULL;      
		if(root == p || root == q)
			return root;
		TreeNode* L = lowestCommonAncestor(root->left, p, q);
		TreeNode* R = lowestCommonAncestor(root->right, p, q);
		if(L && R)
			return root;
		return L ? L : R;
    }
};

  下面我们来分析这个代码的正确性。首先,若p,q两个节点分别在所求节点的左子树,右子树中,则该所求节点是整个二叉树中唯一一个左右节点返回值都不是NULL的节点;若所求节点本身即是p或q节点,则在该节点处会返回该节点的指针,而该遍历该节点的所有祖先节点的返回值都是该节点指针。这确保了这种算法的正确性。

  最后总结一下,这段代码应用了深度搜索的思想和先根遍历的遍历方法,时间复杂度为O(n),形式上也很有美感。感觉Lowest Common Ancestor of a Binary Tree这道题目本身虽然不复杂,但却很能说明一些问题。

Lowest Common Ancestor of a Binary Tree题解

标签:

原文地址:http://www.cnblogs.com/tiezhibieek/p/4985913.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!