Given a rooted binary tree, return the lowest common ancestor of its deepest leaves.html
Recall that:node
d
, the depth of each of its children is d+1
.S
of nodes is the node A
with the largest depth such that every node in S is in the subtree with root A
.Example 1:git
Input: root = [1,2,3] Output: [1,2,3] Explanation: The deepest leaves are the nodes with values 2 and 3. The lowest common ancestor of these leaves is the node with value 1. The answer returned is a TreeNode object (not an array) with serialization "[1,2,3]".
Example 2:github
Input: root = [1,2,3,4] Output: [4]
Example 3:函数
Input: root = [1,2,3,4,5] Output: [2,4,5]
Constraints:code
这道题让咱们求一棵二叉树中最深叶结点的最小公共父结点 Lowest Common Ancestor,在 LeetCode 中,有两道关于 LCA 的题,分别是 Lowest Common Ancestor of a Binary Tree 和 Lowest Common Ancestor of a Binary Search Tree,可是显然这道题要更加的复杂一些,由于最深的叶结点的个数不肯定,可能会有1个,2个,甚至多个,那么其最小公共父节点的位置也就有多种可能的位置。对于二叉树的问题,刷题老司机们应该都知道,十有八九都是用递归来作,这道题也不例外。在毫无头绪的时候,就先从最简单的状况开始分析吧,假如 root 为空,则直接返回 nullptr,假如 root 没有子结点,其自己就是最深叶结点,返回 root。若 root 有左右子结点,说明左右子树存在,一般状况下咱们会对左右子结点调用递归,那么返回的就是左右子树分别的最深叶结点的最小公共父节点,可是问题来了,就算分别知道了左右子树的最深结点的 LCA,怎么推出当前树的 LCA?若左子树的最深叶结点的深度更深,则应该返回左子树的 LCA,若右子树的最深叶结点的深度更深,则应该返回右子树的 LCA,若两者同样深,则要返回当前结点。这样的话,对于每一个结点 node,必需要分别知道其左右子树的最深叶结点的深度才行,可使用一个 getDepth 函数来求任意结点到叶结点的最大深度,叶结点自己的深度为0。有了这个函数,就能够对当前结点的左右子结点计算深度,若深度相同,则返回当前结点,不然对深度大的子结点调用递归,怎么隐约感受有些二分搜索法的影子在里面,参见代码以下:htm
解法一:blog
class Solution { public: TreeNode* lcaDeepestLeaves(TreeNode* root) { if (!root) return nullptr; int left = getDepth(root->left), right = getDepth(root->right); if (left == right) return root; return (left > right) ? lcaDeepestLeaves(root->left) : lcaDeepestLeaves(root->right); } int getDepth(TreeNode* node) { if (!node) return 0; return 1 + max(getDepth(node->left), getDepth(node->right)); } };
因为计算深度的函数 getDepth 存在大量的重复计算,可使用一个 HashMap 来保存已经算过深度的结点,这样再次遇到的时候,直接从 HashMap 中取值便可,可使计算效率更高一些,参见代码以下:递归
解法二:leetcode
class Solution { public: unordered_map<TreeNode*, int> m; TreeNode* lcaDeepestLeaves(TreeNode* root) { if (!root) return nullptr; int left = getDepth(root->left, m), right = getDepth(root->right, m); if (left == right) return root; return (left > right) ? lcaDeepestLeaves(root->left) : lcaDeepestLeaves(root->right); } int getDepth(TreeNode* node, unordered_map<TreeNode*, int>& m) { if (!node) return 0; if (m.count(node)) return m[node]; return m[node] = 1 + max(getDepth(node->left, m), getDepth(node->right, m)); } };
咱们也能够把计算 LCA 和深度放到一个子函数中,让子函数 helper 既返回以当前结点为根结点的子树的最深叶结点的 LCA,又返回当前结点的深度。在递归函数 helper 中,首先判空,若为空,则返回由 nullptr 和0组成的 pair 对儿。不然分别对左右子结点调用递归函数,若左结点的深度大,则返回左子结点和左子结点深度加1组成的 pair 对儿;若右子结点的深度大,则返回右子结点和右子结点深度加1组成的 pair 对儿;剩下的状况就是左右子结点的深度相同,返回当前结点和左子结点深度加1组成的 pair 对儿便可,参见代码以下:
解法三:
class Solution { public: TreeNode* lcaDeepestLeaves(TreeNode* root) { return helper(root).first; } pair<TreeNode*, int> helper(TreeNode* node) { if (!node) return {nullptr, 0}; auto left = helper(node->left), right = helper(node->right); if (left.second > right.second) return {left.first, left.second + 1}; if (left.second < right.second) return {right.first, right.second + 1}; return {node, left.second + 1}; } };
再来看一种很相似的写法,这里用了两个全局变量,全局最深叶结点的最小公共父节点 res,以及全局的最大深度 deepest。跟上面的解法思路很相似,也是在递归函数 helper 中既算 lCA 又算深度,同时还要更新全局的 res 和 deepest。递归函数还须要一个参数 cur,用来保存当前结点的深度,首先用 cur 来更新最大深度 deepest,再判空,若 node 为空,直接返回 cur。再对左右子结点调用递归函数,假如此时左右子结点返回的深度都等于最大深度 deepest,说明当前结点 node 就是要求的 LCA,赋值给结果 res,而后返回 left 和 right 中的较大值,就是当前结点 node 的深度,参见代码以下:
解法四:
class Solution { public: TreeNode* lcaDeepestLeaves(TreeNode* root) { TreeNode *res; int deepest = 0; helper(root, 0, deepest, res); return res; } int helper(TreeNode* node, int cur, int& deepest, TreeNode*& res) { deepest = max(deepest, cur); if (!node) return cur; int left = helper(node->left, cur + 1, deepest, res); int right = helper(node->right, cur + 1, deepest, res); if (left == deepest && right == deepest) { res = node; } return max(left, right); } };
Github 同步地址:
https://github.com/grandyang/leetcode/issues/1123
相似题目:
Lowest Common Ancestor of a Binary Tree
Lowest Common Ancestor of a Binary Search Tree
参考资料:
https://leetcode.com/problems/lowest-common-ancestor-of-deepest-leaves/