二叉樹LCA--leetcode236題

二叉樹的最近公共祖先

給定一個二叉樹, 找到該樹中兩個指定節點的最近公共祖先。
百度百科中最近公共祖先的定義爲:“對於有根樹 T 的兩個結點 p、q,最近公共祖先表示爲一個結點 x,滿足 x 是 p、q 的祖先且 x 的深度儘可能大(一個節點也可以是它自己的祖先)。”
例如,給定如下二叉樹: root = [3,5,1,6,2,0,8,null,null,7,4]

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

1.哈希表解法
(1)創建隊列queue進行二叉樹層序遍歷
(2)設置map映射父子結點關係,從而可以從子結點訪問到父節點
(3)利用map記錄的聯繫找出p所有的祖宗結點存在set
(4)遍歷q的父節點,如果存在於set中,則爲最近公共祖先,直接返回

var lowestCommonAncestor = function (root, p, q) {
    /* 如果root爲p或q直接返回 */
    if (!root || root === p || root === q) return root;
    let queue = [root];
    let map = new WeakMap();
    /* 遍歷二叉樹,存映射關係 */
    while (queue.length) {
        let size = queue.length;
        while (size--) {
            let front = queue.shift();/* 隊首 */
            if (front.left) {
                queue.push(front.left);
                map.set(front.left, front);
            }
            if (front.right) {
                queue.push(front.right);
                map.set(front.right, front);
            }
        }
    }
    /* 記錄p的所有祖先 */
    let acts = new Set();
    while (p) {
        acts.add(p);//放到set中
        p = map.get(p);//父結點
    }
    /* 查找公共祖先 */
    while (q) {
        if (acts.has(q)) return q;
        q = map.get(q);
    }
};

2.深度優先搜索解法
原理:根據p,q是否分別在兩側子樹判斷LCA
(1)深度優先遍歷二叉樹,如果當前節點爲 p 或者 q,直接返回這個節點,
(2)不符合以上條件,查看左右孩子,左孩子中不包含 pq 則去找右孩子,右孩子不包含 p 或者 q 就去找左孩子
(3)左右孩子中都存在 p 或者 q, 那麼這個節點就是LCA(只有對於最近公共祖先p,q纔會在不同側)

var lowestCommonAncestor = function (root, p, q) {
    /* root爲null,p,q這三種情況時返回 */
    if (!root || root === p || root === q) return root;
    /* 查找左子樹 */
    let left = lowestCommonAncestor(root.left, p, q);
    /* 查找右子樹 */
    let right = lowestCommonAncestor(root.right, p, q);
    /* 左子樹不存在p/q */
    if (!left) return right;
    else if (!right) return left;
    else return root;//左右子樹各存在p,q中的一個,爲公共祖先
};

補充

對於二叉搜索樹,還可以進行優化,通過權值大小比對可以確定p,q相對root的位置,如果p,q分別在root的兩側,則root就是最近公共祖先。
題目鏈接:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree/submissions/
遞歸法:

var lowestCommonAncestor = function (root, p, q) {
    if (!root || root === p || root === q) return root;
    /* 判斷p,q在root的哪邊,如果一左一右則root就是最近公共祖先 */
    if (root.val > p.val && root.val > q.val) {
        return lowestCommonAncestor(root.left, p, q);
    }
    else if (root.val < p.val && root.val < q.val) {
        return lowestCommonAncestor(root.right, p, q);
    }
    else {
        return root;
    }
};

非遞歸:

var lowestCommonAncestor = function (root, p, q) {
    if (!root || root === p || root === q) return root;
    while (root) {
        if (root.val > p.val && root.val > q.val) {
            root = root.left;
        } else if (root.val < p.val && root.val < q.val) {
            root = root.right;
        } else {
            return root;
        }
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章