代碼題(30)— 二叉搜索樹、二叉樹的最近公共祖先


1、235. 二叉搜索樹的最近公共祖先

給定一個二叉搜索樹, 找到該樹中兩個指定節點的最近公共祖先。

最近公共祖先的定義為:“對於有根樹 T 的兩個結點 p、q,最近公共祖先表示為一個結點 x,滿足 x 是 p、q 的祖先且 x 的深度盡可能大(一個節點也可以是它自己的祖先)。”

例如,給定如下二叉搜索樹:  root = [6,2,8,0,4,7,9,null,null,3,5]

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

示例 1:

輸入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
輸出: 6 
解釋: 節點 2 和節點 8 的最近公共祖先是 6。

示例 2:

輸入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
輸出: 2
解釋: 節點 2 和節點 4 的最近公共祖先是 2, 因為根據定義最近公共祖先節點可以為節點本身。

  這道題我們可以用遞歸來求解,我們首先來看題目中給的例子,由於二叉搜索樹的特點是左<根<右,所以根節點的值一直都是中間值,大於左子樹的所有節點值,小於右子樹的所有節點值,那么我們可以做如下的判斷,如果根節點的值大於p和q之間的較大值,說明p和q都在左子樹中,那么此時我們就進入根節點的左子節點繼續遞歸,如果根節點小於p和q之間的較小值,說明p和q都在右子樹中,那么此時我們就進入根節點的右子節點繼續遞歸,如果都不是,則說明當前根節點就是最小共同父節點,直接返回即可。

/**
 * 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 nullptr;
        if(root->val > max(p->val, q->val))
            return lowestCommonAncestor(root->left, p, q);
        else if(root->val < min(p->val, q->val))
            return lowestCommonAncestor(root->right, p, q);
        else 
            return root;
    }
};

 

2、236. 二叉樹的最近公共祖先

給定一個二叉樹, 找到該樹中兩個指定節點的最近公共祖先。

百度百科中最近公共祖先的定義為:“對於有根樹 T 的兩個結點 p、q,最近公共祖先表示為一個結點 x,滿足 x 是 p、q 的祖先且 x 的深度盡可能大(一個節點也可以是它自己的祖先)。”

例如,給定如下二叉樹:  root = [3,5,1,6,2,0,8,null,null,7,4]

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

示例 1:

輸入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
輸出: 3
解釋: 節點 5 和節點 1 的最近公共祖先是節點 3。

示例 2:

輸入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
輸出: 5
解釋: 節點 5 和節點 4 的最近公共祖先是節點 5。因為根據定義最近公共祖先節點可以為節點本身。

  所以我們只能在二叉樹中來搜索p和q,然后從路徑中找到最后一個相同的節點即為父節點,我們可以用遞歸來實現,在遞歸函數中,我們首先看當前結點是否為空,若為空則直接返回空,若為p或q中的任意一個,也直接返回當前結點。否則的話就對齊左右子結點分別調用遞歸函數,由於這道題限制了p和q一定都在二叉樹中存在,那么如果當前結點不等於p或q,那么p和q要么分別位於左右子樹中,要么同時位於左子樹,或者同時位於右子樹,那么我們分別來討論:

  若p和q要么分別位於左右子樹中,那么對左右子結點調用遞歸函數,會分別返回p和q結點的位置,而當前結點正好就是p和q的最小共同父結點,直接返回當前結點即可,這就是題目中的例子1的情況。

  若p和q同時位於左子樹,這里有兩種情況,一種情況是left會返回p和q中較高的那個位置,而right會返回空,所以我們最終返回非空的left即可,這就是題目中的例子2的情況。還有一種情況是會返回p和q的最小父結點,就是說當前結點的左子樹中的某個結點才是p和q的最小父結點,會被返回。

  若p和q同時位於右子樹,同樣這里有兩種情況,一種情況是right會返回p和q中較高的那個位置,而left會返回空,所以我們最終返回非空的right即可,還有一種情況是會返回p和q的最小父結點,就是說當前結點的右子樹中的某個結點才是p和q的最小父結點,會被返回,寫法很簡潔,

  上述代碼可以進行優化一下,如果當前結點不為空,且既不是p也不是q,那么根據上面的分析,p和q的位置就有三種情況,p和q要么分別位於左右子樹中,要么同時位於左子樹,或者同時位於右子樹。我們需要優化的情況就是當p和q同時為於左子樹或右子樹中,而且返回的結點並不是p或q,那么就是p和q的最小父結點了,已經求出來了,就不用再對右結點調用遞歸函數了,同樣,對返回的right也做同樣的優化處理。

/**
 * 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 || p==root || q==root)
            return root;
        TreeNode* left = lowestCommonAncestor(root->left, p, q);
//優化添加的
if(left && left != p && left != q) return left;
TreeNode
* right = lowestCommonAncestor(root->right, p, q);
//優化添加的
if(right && right != p && right != q) return right;
if(left && right) return root; return left ? left : right; } };

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM