樹+8道前端算法面試高頻題解

樹的相關名詞科普

  • 根節點
  • 葉子節點
  • 父節點
  • 子節點
  • 兄弟節點
  • 高度
  • 深度

A 是 根節點。C、D、F、G 是 葉子節點。A 是 B 和 E 的 父節點。B 和 E 是 A 的 子節點。B、E 之間是 兄弟節點javascript

高度、深度、層 如上圖所示。前端

爲了方便理解記憶,高度就是擡頭看,深度就是低頭看。java

高度、深度 不一樣, 類比盜夢空間裏的樓,樓都是從 1 層開始計算,盜夢空間中的樓顛倒過來,從上往下。node

開啓刷題

年初立了一個 flag,上面這個倉庫在 2021 年寫滿 100 道前端面試高頻題解,目前進度已經完成了 50%git

若是你也準備刷或者正在刷 LeetCode,不妨加入前端食堂,一塊兒並肩做戰,刷個痛快。github

瞭解了樹的基礎知識後,立刻開啓咱們愉快的刷題之旅,我整理了 8 道高頻的 LeetCode 鏈表題及題解以下。面試

01 二叉樹的中序遍歷

原題連接數組

中序遍歷:先打印當前節點的左子樹,再打印當前節點,最後打印當前節點的右子樹 (CBDAFEG),如上圖。post

const inorderTraversal = function(root) {
    const result = [];
    function pushRoot(root) {
        if (root !== null) {
            if (root.left !== null) {
                pushRoot(root.left);
            }
            result.push(root.val);
            if (root.right !== null) { 
                pushRoot(root.right);
            }
        }
    }
    pushRoot(root);
    return result;
};
  • 時間複雜度: O(n)
  • 空間複雜度: O(n)

02 二叉樹的前序遍歷

原題連接spa

前序遍歷:先打印當前節點,再打印當前節點的左子樹,最後打印當前節點的右子樹 (ABCDEFG),如上圖。

const preorderTraversal = function(root) {
    const result = [];
    function pushRoot(node){
        if (node !== null) {
            result.push(node.val);
            if (node.left !== null){ 
                pushRoot(node.left);
            }
            if (node.right !== null) {
                pushRoot(node.right);
            } 
        }
    }
    pushRoot(root);
    return result;
};
  • 時間複雜度: O(n)
  • 空間複雜度: O(n)

03 二叉樹的後序遍歷

原題連接

後序遍歷:先打印當前節點的左子樹,再打印當前節點的右子樹,最後打印當前節點 (CDBFGEA),如上圖。

const postorderTraversal = function(root) {
    const result = [];
    function pushRoot(node) {
        if (node !== null) {
            if (node.left !== null) {
                pushRoot(node.left);
            }
            if (node.right !== null) {
                pushRoot(node.right);
            } 
            result.push(node.val);
        }
    }
    pushRoot(root);
    return result;
};
  • 時間複雜度: O(n)
  • 空間複雜度: O(n)

04 相同的樹

原題連接

深度優先搜索 DFS

  1. 若是兩個二叉樹都爲空,則它們相同返回 true。
  2. 若是兩個二叉樹中有一個爲空,則它們不一樣返回 false。
  3. 若是兩個二叉樹都不爲空,首先判斷根節點是否相同,不一樣則返回 false。
  4. 若是兩個二叉樹的根節點相同,則分別遞歸判斷其左右子樹是否相同。
const isSameTree = function(p, q) {
    if (p === null && q === null) return true;
    if (p === null || q === null) return false;
    if (p.val !== q.val) return false;
    return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
};
  • 時間複雜度: O(min(m, n))
  • 空間複雜度: O(min(m, n))

05 對稱二叉樹

原題連接

遞歸

先明確,所謂「對稱」,也就是兩個樹的根節點相同

  • 第一個樹的左子樹與第二個樹的右子樹鏡像對稱。
  • 第一個樹的右子樹與第二個樹的左子樹鏡像對稱。
const isSymmetric = function(root) {
    if (root === null) return true
    return isEqual(root.left, root.right) // 比較左右子樹是否對稱
};

const isEqual = function(left, right) {
    // 遞歸終止條件
    if (left === null && right === null) return true // 對稱
    if (left === null || right === null) return false // 不對稱
    // 比較左右子樹的 root 值以及左右子樹是否對稱
    return left.val === right.val
        && isEqual(left.left, right.right)
        && isEqual(left.right, right.left)
}
  • 時間複雜度: O(n)
  • 空間複雜度: O(n)

06 二叉樹的層序遍歷

原題連接

DFS 深度優先遍歷

按照樹的深度將每層對應的節點添加到對應層的數組中便可。

const levelOrder = function(root) {
    if (!root) return []
    const res = []
    dfs(root, 0, res)
    return res
};

const dfs = function(root, depth, res) {
    if (!root) return // 遞歸終止條件
    if (!res[depth]) res[depth] = []
    res[depth].push(root.val) // 存入每層的節點值
    dfs(root.left, depth + 1, res) // drill down
    dfs(root.right, depth + 1, res)
}

BFS 廣度優先遍歷

根據層次返回其對應的結果集合。

  1. 邊界處理,初始化隊列 queue 和存放結果的數組 res。
  2. 外層循環遍歷層級結構,內層循環遍歷每一層的子節點。
  3. 遍歷時須要記錄當前層的遍歷次數 len 以及當前層的節點數組 arr。
  4. 取得 node 依次出隊,並依次存入當前層的節點數組中。
  5. 若存在左右子節點,則依次入隊,並更新 len。
  6. 遍歷完後返回結果 res。
const levelOrder = function(root) {
    if (!root) return []
    const queue = [root]
    const res = []
    while (queue.length > 0) {
      const arr = []
      let len = queue.length
      while (len) {
        let node = queue.shift()
        arr.push(node.val)
        if (node.left) queue.push(node.left)
        if (node.right) queue.push(node.right)
        len--
      }
      res.push(arr)
    }
    return res
};
  • 時間複雜度: O(n)
  • 空間複雜度: O(n)

07 二叉樹的最大深度

原題連接

DFS 深度優先搜索

樹的深度 = 左右子樹的最大深度 + 1

const maxDepth = function(root) {
    if (!root) { // 遞歸終止條件
        return 0
    } else {
        const left = maxDepth(root.left)
        const right = maxDepth(root.right)
        return Math.max(left, right) + 1
    }
};
  • 時間複雜度: O(n)
  • 最壞空間複雜度: O(height), height 表示二叉樹的高度

BFS 廣度優先搜索

層序遍歷時記錄樹的深度。

二叉樹的層序遍歷可參考輕鬆拿下二叉樹的層序遍歷

const maxDepth = function(root) {
    let depth = 0
    if (root === null) {
        return depth
    }
    const queue = [root]
    while (queue.length) {
        let len = queue.length
        while (len--) {
            const cur = queue.shift()
            cur.left && queue.push(cur.left)
            cur.right && queue.push(cur.right)
        }
        depth++
    }
    return depth
};
  • 時間複雜度: O(n)
  • 空間複雜度: O(n)

08 翻轉二叉樹

原題連接

Google:咱們 90% 的工程師都用你寫的軟件(Homebrew),但你無法在白板上翻轉二叉樹,因此翻滾吧,蛋炒飯。

原推截圖,至今仍在。 Max Howell 當年吐槽以後 LeetCode 立刻加入了這道題。

會了這道題,是否是咱們也能夠超越世界級大牛了?(狗頭保命)

首先明確,所謂二叉樹的翻轉須要知足如下兩點:

  1. 它的左右子樹要交換位置。
  2. 而且左右子樹內部的全部子樹或是結點都要進行交換位置。

遞歸

  1. 從根節點開始,遞歸的對樹進行遍歷。
  2. 從葉子結點開始進行翻轉。
  3. 左右子樹都已經翻轉後,交換兩棵子樹的位置便可完成所有的翻轉。
const invertTree = function(root) {
    if (root === null) return null // 遞歸終止條件
    invertTree(root.left)
    invertTree(root.right)
    const temp = root.left
    root.left = root.right
    root.right = temp
    return root
}
  • 時間複雜度: O(n)
  • 空間複雜度: O(n)

固然你也能夠將上面的 2,3 兩個步驟顛倒執行,也就是先交換兩棵子樹的位置,再對其內部進行翻轉。

const invertTree = function(root) {
    if (root === null) return null // 遞歸終止條件
    const temp = root.left
    root.left = root.right
    root.right = temp
    invertTree(root.left)
    invertTree(root.right)
    return root
}

BFS

層序遍歷遍歷二叉樹,當根結點出列時,翻轉它的左右子樹。而後將其左右子節點入列,以便下一層時翻轉。

二叉樹的層序遍歷可參考輕鬆拿下二叉樹的層序遍歷

const invertTree = (root) => {
  if (root == null) return null;
  const queue = [root];
  while (queue.length) {
    const cur = queue.shift();
    [cur.left, cur.right] = [cur.right, cur.left];
    if (cur.left) queue.push(cur.left);
    if (cur.right) queue.push(cur.right);
  }
  return root;
}

image

相關文章
相關標籤/搜索