当前位置:   article > 正文

Leetcode 236 二叉树的最近公共祖先

Leetcode 236 二叉树的最近公共祖先

题意理解:

        二叉树的最近公共祖先: 简单理解,就是p和q值的那两个节点,不断向上返回,然后会在一个点汇合,那么他们第一次汇合的这个点就是他们的最近公共祖先。

解题的思路就是:

        如果这一层找到了p或q的值,就向上一层返回。

        如果父节点的左右分别找了p、q节点,则返回父节点

        如果父节点占p、q中的一个,然后子树中找到一个,则返回父节点

        否则返回null

解题方法:

        其实就是树的话,一般都可以用递归和迭代两种方法的,就是这道题,用迭代比较难理解一点。

1.递归

先判断子树是否找到p、q值,再判断中间节点是否需要返回,所以处理顺序为: 左子树、右子树、中间节点——后续遍历

对于这道题来说,递归的思路看起来更为明确。

  1. /**
  2. * 什么是最近公共祖先?
  3. * 两个值节点合并到一棵树的那个祖先节点
  4. * 题目限制:树中没有重复值,p,q一定存在,这使得题目简单了不少
  5. * 思路:找到一个p|q,则向上返回,当遇到某个节点,左子树,右子树返回都不为null时,
  6. * 说明该节点是最近祖先,向上返回,
  7. * 最终返回最近祖先
  8. * @param root
  9. * @param p
  10. * @param q
  11. * @return
  12. */
  13. public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
  14. //由于题目限制,root一定不为null
  15. //由于需要对左右子树进行判断,然后对中间节点进行处理,故使用后序遍历:左右中
  16. //左处理
  17. TreeNode leftResult=root.left!=null?lowestCommonAncestor(root.left,p,q):null;
  18. //右处理
  19. TreeNode rightResult=root.right!=null?lowestCommonAncestor(root.right,p,q):null;
  20. //中间处理
  21. if(root.val==p.val||root.val==q.val) return root;
  22. //左右结果均不为空,则说明左右子树各找到一个目标值
  23. // 因为pq一定存在,p!=q,且树中没有重复值,故上述结论一定成立
  24. if(Objects.nonNull(leftResult)&&Objects.nonNull(rightResult)) return root;
  25. //左右找到一个,即该子树仅存在p|q中一个,继续向上返回
  26. else if(Objects.nonNull(leftResult)&&Objects.isNull(rightResult)) return leftResult;
  27. else if(Objects.isNull(leftResult)&&Objects.nonNull(rightResult)) return rightResult;
  28. //左右都没有找到,则说明该子树没有目标值,返回null
  29. else return null;
  30. /**
  31. * //中间处理逻辑精简
  32. * if(root.val==p.val||root.val==q.val||(Objects.nonNull(leftResult)&&Objects.nonNull(rightResult))) return root;
  33. * //左右找到一个,即该子树仅存在p|q中一个,继续向上返回
  34. * else if(Objects.nonNull(leftResult)&&Objects.isNull(rightResult)) return leftResult;
  35. * else if(Objects.isNull(leftResult)&&Objects.nonNull(rightResult)) return rightResult;
  36. * //左右都没有找到,则说明该子树没有目标值,返回null
  37. * else return null;
  38. */
  39. }

2.迭代

不建议用迭代,理解太复杂,除非有要求。

这里需要两个栈,一个栈用来维护遍历树的操作。

另一个栈用来描述找到的节点在树种的位置关系,用来向上返回找到的值,且可以用来判断找到的两个节点是否在此处汇合。

eg:   null null null 3 9 null 即可表示要找的值在同一层,一个null表示即将出现一个中间节点,两值汇合后的下一个null出现时对应的中间节点,即为汇合点,即最近公共祖先

  1. //迭代
  2. public TreeNode lowestCommonAncestor2(TreeNode root, TreeNode p, TreeNode q) {
  3. //自定义栈-模拟递归
  4. Stack<TreeNode> stack=new Stack<>();
  5. //暂存找到的值,并指示层级
  6. Stack<TreeNode> resultStack=new Stack<>();
  7. stack.push(root);
  8. while(!stack.isEmpty()){
  9. TreeNode cur=stack.pop();
  10. if (Objects.nonNull(cur)) {
  11. //节点入栈
  12. stack.push(cur);
  13. stack.push(null);
  14. resultStack.push(null);//每加一个null相当于一层,用于只是层级
  15. //保证后序遍历的顺序入栈
  16. if(Objects.nonNull(cur.right)) stack.push(cur.right);
  17. if(Objects.nonNull(cur.left)) stack.push(cur.left);
  18. }else{
  19. //碰到中间节点
  20. cur=stack.pop();
  21. //该层有找到的值加入结果暂存层
  22. if(cur.val==p.val||cur.val==q.val){
  23. resultStack.push(cur);
  24. }
  25. TreeNode node=resultStack.pop();
  26. if(node!=null){//该层有找到的值
  27. if(resultStack.peek()!=null) return cur;//该层找到两个值
  28. else {
  29. resultStack.pop();//该层找到一个值,上移
  30. resultStack.push(node);
  31. }
  32. }
  33. }
  34. }
  35. return null;
  36. }

3.分析

时间复杂度:

        递归:O(n)

        迭代:O(n)

空间复杂度:

        递归:O(n)

        迭代:O(2n)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/84971
推荐阅读
相关标签
  

闽ICP备14008679号