蘋果遭反壟斷訴訟,因 Apple Watch 心率監測不支援第三方 App
給定一個二叉樹, 找到該樹中兩個指定節點的最近公共祖先。
百度百科中最近公共祖先的定義為:“對於有根樹 T 的兩個節點 p、q,最近公共祖先表示為一個節點 x,滿足 x 是 p、q 的祖先且 x 的深度儘可能大(一個節點也可以是它自己的祖先)。”
示例 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 。因為根據定義最近公共祖先節點可以為節點本身。
解法一:遞迴 深度搜索
通過深度搜索,不斷遞迴,如果搜尋到要查詢的節點,那麼返回true,同時左右節點中如果存在要查詢的節點,也返回true,最大深度公共節點滿足的條件是,左右子樹都是true,或者根節點是要查詢的節點並且左右子樹存在一個為true
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root == NULL) return NULL; //遞迴邊界
if(root == p || root == q) return root;
//分解為求左子樹的子問題和右子樹的子問題,注意是後序遍歷
TreeNode* left_have = lowestCommonAncestor(root->left,p,q);
TreeNode* right_have = lowestCommonAncestor(root->right,p,q);
if(left_have && right_have) return root; //左右子樹都有則返回root
else return left_have ? left_have : right_have; //如果左右子樹中有一個子問題沒得到結果,則返回得到結果的子問題.
}
複雜度分析
時間複雜度:O(N)O(N),其中 NN 是二叉樹的節點數。二叉樹的所有節點有且只會被訪問一次,因此時間複雜度為 O(N)O(N)。
空間複雜度:O(N)O(N) ,其中 NN 是二叉樹的節點數。遞迴呼叫的棧深度取決於二叉樹的高度,二叉樹最壞情況下為一條鏈,此時高度為 NN,因此空間複雜度為 O(N)O(N)。
解法二:記錄父節點
首先把為所有節點建立和父節點的關聯,然後通過hash表查詢要查詢節點的父節點,並且儲存在map中,通過對比找到父節點
Map<Integer, TreeNode> parent = new HashMap<Integer, TreeNode>(); Set<Integer> visited = new HashSet<Integer>(); public void dfs(TreeNode root) { if (root.left != null) { parent.put(root.left.val, root); dfs(root.left); } if (root.right != null) { parent.put(root.right.val, root); dfs(root.right); } } public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { dfs(root); while (p != null) { visited.add(p.val); p = parent.get(p.val); } while (q != null) { if (visited.contains(q.val)) { return q; } q = parent.get(q.val); } return null; }
複雜度分析
時間複雜度:O(N)O(N),其中 NN 是二叉樹的節點數。二叉樹的所有節點有且只會被訪問一次,從 p 和 q 節點往上跳經過的祖先節點個數不會超過 NN,因此總的時間複雜度為 O(N)O(N)。
空間複雜度:O(N)O(N) ,其中 NN 是二叉樹的節點數。遞迴呼叫的棧深度取決於二叉樹的高度,二叉樹最壞情況下為一條鏈,此時高度為 NN,因此空間複雜度為 O(N)O(N),雜湊表儲存每個節點的父節點也需要 O(N)O(N) 的空間複雜度,因此最後總的空間複雜度為 O(N)O(N)。