236、二叉樹的最近公共祖先 | 演算法(leetcode,附思維導圖 + 全部解法)300題

碼農三少 發表於 2022-06-11
演算法 LeetCode

零 標題:演算法(leetcode,附思維導圖 + 全部解法)300題之(236)二叉樹的最近公共祖先

一 題目描述

題目描述
題目描述


題目描述

二 解法總覽(思維導圖)

思維導圖

三 全部解法

1 方案1

1)程式碼:

// 方案1 “自己。遞迴-儲存所有路徑法”。

// 思路:
// 1)狀態初始化:resList = [], curPpath = []; 。
// 2)呼叫遞迴函式。
// 3)核心:依次從底下往上找 p、q 的公共祖先。
var lowestCommonAncestor = function(curRoot, p, q) {
    // 遞迴函式
    var dfs = function(curPath, curRroot){
        const {left, right} = curRroot;
        curPath.push(curRroot);
        
        // 1)遞迴出口。
        if (left === null && right === null) {
            resList.push(curPath.slice());
            return;
        }

        // 2)遞迴主體。
        if (left === null && right !== null) {
            dfs(curPath, right);
            curPath.pop();
        }
        else if (left !== null && right === null) {
            dfs(curPath, left);
            curPath.pop();
        }
        else {
            dfs(curPath, left);
            curPath.pop();
            dfs(curPath, right);
            curPath.pop();
        }
    }

    // 1)狀態初始化:resList = [], curPpath = []; 。
    let resList = [],
        curPath = [];

    // 2)呼叫遞迴函式。
    dfs(curPath, curRoot);

    // 3)核心:依次從底下往上找 p、q 的公共祖先。
    let p_path = resList.filter(item => item.includes(p))[0],
        q_path = resList.filter(item => item.includes(q))[0];
    
    for(let i = p_path.indexOf(p); i >= 0; i--){
        if(q_path.slice(0, q_path.indexOf(q) + 1).includes(p_path[i])){
            return p_path[i];
        }
    }
};

2 方案2

1)程式碼:

// 方案2 “遞迴法”。
// 參考:
// 1)https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/solution/er-cha-shu-de-zui-jin-gong-gong-zu-xian-by-leetc-2/

// 思路:
// 1)狀態初始化:resNode = null; 。
// 2)呼叫遞迴函式 dfs(root, p, q); 。
// 3)返回結果 resNode 。
var lowestCommonAncestor = function(root, p, q) {
    const dfs = (curRoot, p, q) => {
        // 1)遞迴出口。
        if(curRoot == null){
            return false;
        }

        // 2)遞迴主體。
        let inCurrentNode = curRoot === p || curRoot === q,
            inLeft = dfs(curRoot.left, p, q),
            inRight = dfs(curRoot.right, p, q);
        
        if((inLeft && inRight) || (inCurrentNode)){
            resNode = curRoot;
        }
        return inLeft || inRight || inCurrentNode;
    }

    // 1)狀態初始化:resNode = null; 。
    let resNode = null;

    // 2)呼叫遞迴函式 dfs(root, p, q); 。
    dfs(root, p, q);

    // 3)返回結果 resNode 。
    return resNode;
};

3 方案3

1)程式碼:

// 方案3 “儲存父節點法”。
// 參考:
// 1)https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/solution/er-cha-shu-de-zui-jin-gong-gong-zu-xian-by-leetc-2/
// TODO:重新手撕。

// 思路:
// 1)狀態初始化:resParentMap = new Map(), visitedSet = new Set() 。
// 2)呼叫遞迴函式 dfs(root); 。
// 3)核心處理:暫略(TODO)。
var lowestCommonAncestor = function(root, p, q) {
    const dfs = (curRroot = null) => {
        const {left, right} = curRroot;
        
        if (left !== null) {
            resParentMap.set(left.val, curRroot);
            dfs(left);
        }

        if (right !== null) {
            resParentMap.set(right.val, curRroot);
            dfs(right);
        }
    };

    // 1)狀態初始化:resParentMap = new Map(), visitedSet = new Set() 。
    let resParentMap = new Map(),
        visitedSet = new Set();
    
    // 2)呼叫遞迴函式 dfs(root); 。
    dfs(root);

    // 3)核心處理:暫略(TODO)。
    while (p != null) {
        visitedSet.add(p.val);
        p = resParentMap.get(p.val);
    }
    while (q != null) {
        if (visitedSet.has(q.val)) {
            return q;
        }
        q = resParentMap.get(q.val);
    }
}

四 資源分享 & 更多

1 歷史文章 - 總覽

歷史文章 - 總覽

刷題進度 - LeetCode:526 / 2662 、《劍指offer》:66 / 66

2 博主簡介

碼農三少 ,一個致力於編寫 極簡、但齊全題解(演算法) 的博主。
專注於 一題多解、結構化思維 ,歡迎一起刷穿 LeetCode ~