Leetcode之236. Lowest Common Ancestor of a Binary Tree Medium

236. Lowest Common Ancestor of a Binary Tree  Medium

https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/css

Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree.node

According to the definition of LCA on Wikipedia: 「The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself).」面試

Given the following binary tree:  root = [3,5,1,6,2,0,8,null,null,7,4]函數

Example 1:優化

Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
Output: 3
Explanation: The LCA of nodes  and  is 
513.

Example 2:spa

Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
Output: 5
Explanation: The LCA of nodes  and  is , since a node can be a descendant of itself according to the LCA definition.545

Note:3d

  • All of the nodes' values will be unique.
  • p and q are different and both values will exist in the binary tree.

分析:指針

首先,樹的問題,每每涉及遞歸,之因此涉及遞歸是由於每一棵樹都是由相同結構的多個子樹構成。本題能夠利用遞歸的方式,至關於從葉子節點開始,遞歸地返回以下信息:當前樹(或子樹)同時包含p和q,則函數返回的結果就是它們的最低公共祖先。若是它們其中之一在子樹當中,則結果是它們中的一個。若是它們都不在子樹裏,則結果返回NULL。code

 

class Solution {
public:
    TreeNode * lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        // 雖然下面兩個if能夠寫到一塊兒,但所表達的意思是不同的
        if (root == nullptr) {
            return nullptr;
        }
        if (p == root || q == root) {
            return root;
        }
        TreeNode* left = lowestCommonAncestor(root->left, p, q);
        TreeNode* right = lowestCommonAncestor(root->right, p, q);
        if (left == nullptr) {  // 若是有一個分支爲空,另外一個不爲空,則返回不爲空的節點
            return right;
        }
        else if (right == nullptr) {
            return left;
        }
        else  // 若是兩個都不爲空,則返回兩者當前最低祖先節點
            return root;
    }
};

總結:blog

書上對這道題的作法麻煩了。首先書上並非二叉樹,而是一顆普通樹,因此next存在一個vector裏。
其次,書上的作法是先找到p和q兩條路徑,從根節點出發到p和q分別構成兩條鏈表;
最後,尋找這兩條鏈表的第一個分叉的地方。

注:

若是本題的樹是二叉搜索樹或者有指向父節點的指針,則思路能更加簡單。

1)若是是二叉搜索樹,咱們只須要從樹的根節點開始和兩個輸入節點進行比較,若是當前節點的值比兩個節點的值都大,那麼最低的共同父節點必定在當前節點的左子樹中,因而下一步遍歷當前節點的左子節點;反之,則遍歷右子節點。這樣,在樹中從上到下找到的第一個在兩個輸入節點的值之間的節點就是最低公共祖先。

2)若是是一棵普通的樹,但有指向父節點的指針,此時問題能夠換成求兩個鏈表的第一個公共節點。

3)書上面試者提供的從上至下遍歷子樹的思路相同,其實並很差,由於會涉及到某些結點的屢次遍歷,一方面我以爲能夠利用相似動態規劃的方法存儲不一樣節點的遍歷結果信息(如用一個字典),下次再用到的時候直接返回結果便可。另外一方面,和麪試者提出的優化方法同樣,利用輔助空間,將從根節點到輸入的兩個節點的路徑分別用兩個鏈表保存,而後將問題轉化爲兩個鏈表最後公共節點(和註釋2相似)。鏈表的實現用的是C++ list,如:list<TreeNode*> path1。本題是另外一種優化思路,自底向上這樣避免了屢次遍歷相同節點,保證了每一個節點只遍歷一次。(有一種動態規劃的思想)

書上思路以下:

面試者是這麼解釋這個思路的:所謂兩個節點的公共祖先,指的是這兩個節點都出如今某個節點的子樹中。咱們能夠從根節點開始遍歷一棵樹,每遍歷到一個節點時,判斷兩個輸入節點是否是在它的子樹中。若是在子樹中,則分別遍歷它的全部子節點,並判斷兩個輸入節點是否是在它們的子樹中。這樣從上到下一直找到的第一個節點,它本身的子樹同時包含兩個輸入的節點而它的子節點卻沒有,那麼該節點就是最低公共祖先。

相關文章
相關標籤/搜索