php网站开发价格,林州市建筑信息平台,删除wordpress有什么影响,网站开发人员分配865. 具有所有最深节点的最小子树
问题描述
给定一个二叉树的根节点 root#xff0c;返回包含所有最深节点的最小子树的根节点。
最深节点#xff1a;距离根节点最远的叶子节点
最小子树#xff1a;满足条件的子树中节点数最少的那个#xff08;如果多个子树包含所有最深节…865. 具有所有最深节点的最小子树问题描述给定一个二叉树的根节点root返回包含所有最深节点的最小子树的根节点。最深节点距离根节点最远的叶子节点最小子树满足条件的子树中节点数最少的那个如果多个子树包含所有最深节点返回深度最大的那个注意一个节点也可以是自己的子树最深节点可能有多个示例输入:root[3,5,1,6,2,0,8,null,null,7,4]输出:[2,7,4]解释:最深节点是7和4包含它们的最小子树根节点是23 / \ 5 1 / \ / \ 6 2 0 8 / \ 7 4输入:root[1]输出:[1]输入:root[0,1,3,null,2]输出:[2]解释:最深节点只有2所以最小子树就是[2]0 / \ 1 3 \ 2算法思路深度优先搜索 返回深度和节点核心最深节点一定在树的最大深度层包含所有最深节点的最小子树 最深节点的最近公共祖先LCA关键如果左右子树的最大深度相等说明最深节点分布在两侧当前节点就是答案如果左子树深度 右子树深度答案在左子树中如果右子树深度 左子树深度答案在右子树中DFS对每个节点递归计算左右子树的最大深度同时返回该子树中包含所有最深节点的最小子树根节点通过比较左右子树深度来决定当前节点是否为答案返回值方法返回一个对象包含子树根节点和最大深度或者使用全局变量记录方法只返回深度代码实现方法一返回深度和节点classSolution{/** * 返回包含所有最深节点的最小子树 * 使用DFS返回每个子树的深度和对应的最小子树根节点 * * param root 二叉树根节点 * return 最小子树的根节点 */publicTreeNodesubtreeWithAllDeepest(TreeNoderoot){Resultresultdfs(root);returnresult.node;}/** * DFS * return Result对象包含子树根节点和最大深度 */privateResultdfs(TreeNodenode){// 空节点深度为0节点为nullif(nodenull){returnnewResult(null,0);}// 递归处理左右子树Resultleftdfs(node.left);Resultrightdfs(node.right);// 如果左子树深度更大答案在左子树中if(left.depthright.depth){returnnewResult(left.node,left.depth1);}// 如果右子树深度更大答案在右子树中elseif(right.depthleft.depth){returnnewResult(right.node,right.depth1);}// 左右子树深度相等当前节点就是答案else{returnnewResult(node,left.depth1);}}/** * 存储子树根节点和深度 */privatestaticclassResult{TreeNodenode;intdepth;Result(TreeNodenode,intdepth){this.nodenode;this.depthdepth;}}}方法二全局变量 返回深度classSolution{privateTreeNoderesult;privateintmaxDepth;/** * 使用全局变量记录 */publicTreeNodesubtreeWithAllDeepest(TreeNoderoot){resultnull;maxDepth-1;dfs(root,0);returnresult;}/** * 返回以node为根的子树的最大深度 * 同时更新全局答案 */privateintdfs(TreeNodenode,intdepth){if(nodenull){returndepth;}// 获取左右子树的最大深度intleftDepthdfs(node.left,depth1);intrightDepthdfs(node.right,depth1);// 当前子树的最大深度intcurrentMaxDepthMath.max(leftDepth,rightDepth);// 如果左右子树深度相等说明当前节点包含所有最深节点if(leftDepthrightDepth){// 更新全局深度更大的优先if(currentMaxDepthmaxDepth){maxDepthcurrentMaxDepth;resultnode;}}returncurrentMaxDepth;}}方法三先找最深节点再找LCAimportjava.util.*;classSolution{/** * 先找到所有最深节点再找它们的LCA */publicTreeNodesubtreeWithAllDeepest(TreeNoderoot){if(rootnull)returnnull;// 找到最大深度intmaxDepthgetMaxDepth(root);// 找到所有最深节点SetTreeNodedeepestNodesnewHashSet();findDeepestNodes(root,deepestNodes,maxDepth,1);// 如果只有一个最深节点直接返回if(deepestNodes.size()1){returndeepestNodes.iterator().next();}// 找所有最深节点的LCAreturnfindLCA(root,deepestNodes);}privateintgetMaxDepth(TreeNodenode){if(nodenull)return0;return1Math.max(getMaxDepth(node.left),getMaxDepth(node.right));}privatevoidfindDeepestNodes(TreeNodenode,SetTreeNodedeepestNodes,intmaxDepth,intcurrentDepth){if(nodenull)return;if(currentDepthmaxDepth){deepestNodes.add(node);return;}findDeepestNodes(node.left,deepestNodes,maxDepth,currentDepth1);findDeepestNodes(node.right,deepestNodes,maxDepth,currentDepth1);}privateTreeNodefindLCA(TreeNodenode,SetTreeNodetargets){if(nodenull)returnnull;// 如果当前节点是最深节点之一if(targets.contains(node)){returnnode;}TreeNodeleftfindLCA(node.left,targets);TreeNoderightfindLCA(node.right,targets);// 如果左右子树都包含目标节点当前节点是LCAif(left!nullright!null){returnnode;}// 否则返回非空的一侧returnleft!null?left:right;}}算法分析时间复杂度O(n)每个节点只被访问一次方法一和二只需要一次DFS遍历方法三需要多次遍历总体仍是O(n)空间复杂度O(h)h是树的高度递归栈空间方法一O(h)递归栈 Result对象方法二O(h)递归栈 全局变量方法三O(n)存储最深节点的Set算法过程1root [3,5,1,6,2,0,8,null,null,7,4]DFS叶子节点6,7,4,0,8返回(node, depth1)节点2left (7,1), right (4,1)深度相等 → 返回(2, 2)节点5left (6,1), right (2,2)right.depth left.depth → 返回(2, 3)节点1left (0,1), right (8,1)深度相等 → 返回(1, 2)根节点3left (2,3), right (1,2)left.depth right.depth → 返回(2, 4)结果节点22root [0,1,3,null,2]DFS节点2返回(2,1)节点1left (null,0), right (2,1)→ 返回(2,2)节点3返回(3,1)根节点0left (2,2), right (3,1)→ 返回(2,3)结果节点2测试用例// TreeNode定义classTreeNode{intval;TreeNodeleft;TreeNoderight;TreeNode(){}TreeNode(intval){this.valval;}TreeNode(intval,TreeNodeleft,TreeNoderight){this.valval;this.leftleft;this.rightright;}}publicclassMain{publicstaticvoidmain(String[]args){SolutionsolutionnewSolution();// 测试用例1标准示例TreeNoderoot1newTreeNode(3);root1.leftnewTreeNode(5);root1.rightnewTreeNode(1);root1.left.leftnewTreeNode(6);root1.left.rightnewTreeNode(2);root1.right.leftnewTreeNode(0);root1.right.rightnewTreeNode(8);root1.left.right.leftnewTreeNode(7);root1.left.right.rightnewTreeNode(4);TreeNoderesult1solution.subtreeWithAllDeepest(root1);System.out.println(Test 1: result1.val);// 2// 测试用例2单节点TreeNoderoot2newTreeNode(1);TreeNoderesult2solution.subtreeWithAllDeepest(root2);System.out.println(Test 2: result2.val);// 1// 测试用例3链状树TreeNoderoot3newTreeNode(0);root3.leftnewTreeNode(1);root3.left.rightnewTreeNode(2);root3.rightnewTreeNode(3);TreeNoderesult3solution.subtreeWithAllDeepest(root3);System.out.println(Test 3: result3.val);// 2// 测试用例4完全平衡树TreeNoderoot4newTreeNode(1);root4.leftnewTreeNode(2);root4.rightnewTreeNode(3);TreeNoderesult4solution.subtreeWithAllDeepest(root4);System.out.println(Test 4: result4.val);// 1// 测试用例5左偏树TreeNoderoot5newTreeNode(1);root5.leftnewTreeNode(2);root5.left.leftnewTreeNode(3);TreeNoderesult5solution.subtreeWithAllDeepest(root5);System.out.println(Test 5: result5.val);// 3// 测试用例6右偏树TreeNoderoot6newTreeNode(1);root6.rightnewTreeNode(2);root6.right.rightnewTreeNode(3);TreeNoderesult6solution.subtreeWithAllDeepest(root6);System.out.println(Test 6: result6.val);// 3// 测试用例7三个最深节点TreeNoderoot7newTreeNode(1);root7.leftnewTreeNode(2);root7.rightnewTreeNode(3);root7.left.leftnewTreeNode(4);root7.left.rightnewTreeNode(5);root7.right.leftnewTreeNode(6);TreeNoderesult7solution.subtreeWithAllDeepest(root7);System.out.println(Test 7: result7.val);// 1}}关键点深度相等左右子树深度相等说明最深节点分布在两侧当前节点是这些最深节点的最近公共祖先为什么深度更大的优先要求最小子树在多个满足条件的子树中深度更大的子树包含的节点更少。递归通过比较子树深度找到了包含所有最深节点的最小子树不需要显式找到所有最深节点边界处理空树返回null单节点返回自身只有一个最深节点返回该节点常见问题为什么不用先找到所有最深节点再找LCA需要额外的存储空间和多次遍历。DFS一次遍历更高效。时间复杂度为什么是O(n)每个节点只被访问一次。