赞
踩
题意理解:
二叉树的最近公共祖先: 简单理解,就是p和q值的那两个节点,不断向上返回,然后会在一个点汇合,那么他们第一次汇合的这个点就是他们的最近公共祖先。
解题的思路就是:
如果这一层找到了p或q的值,就向上一层返回。
如果父节点的左右分别找了p、q节点,则返回父节点
如果父节点占p、q中的一个,然后子树中找到一个,则返回父节点
否则返回null
解题方法:
其实就是树的话,一般都可以用递归和迭代两种方法的,就是这道题,用迭代比较难理解一点。
先判断子树是否找到p、q值,再判断中间节点是否需要返回,所以处理顺序为: 左子树、右子树、中间节点——后续遍历
对于这道题来说,递归的思路看起来更为明确。
- /**
- * 什么是最近公共祖先?
- * 两个值节点合并到一棵树的那个祖先节点
- * 题目限制:树中没有重复值,p,q一定存在,这使得题目简单了不少
- * 思路:找到一个p|q,则向上返回,当遇到某个节点,左子树,右子树返回都不为null时,
- * 说明该节点是最近祖先,向上返回,
- * 最终返回最近祖先
- * @param root
- * @param p
- * @param q
- * @return
- */
- public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
- //由于题目限制,root一定不为null
- //由于需要对左右子树进行判断,然后对中间节点进行处理,故使用后序遍历:左右中
- //左处理
- TreeNode leftResult=root.left!=null?lowestCommonAncestor(root.left,p,q):null;
- //右处理
- TreeNode rightResult=root.right!=null?lowestCommonAncestor(root.right,p,q):null;
- //中间处理
- if(root.val==p.val||root.val==q.val) return root;
- //左右结果均不为空,则说明左右子树各找到一个目标值
- // 因为pq一定存在,p!=q,且树中没有重复值,故上述结论一定成立
- if(Objects.nonNull(leftResult)&&Objects.nonNull(rightResult)) return root;
- //左右找到一个,即该子树仅存在p|q中一个,继续向上返回
- else if(Objects.nonNull(leftResult)&&Objects.isNull(rightResult)) return leftResult;
- else if(Objects.isNull(leftResult)&&Objects.nonNull(rightResult)) return rightResult;
- //左右都没有找到,则说明该子树没有目标值,返回null
- else return null;
-
-
- /**
- * //中间处理逻辑精简
- * if(root.val==p.val||root.val==q.val||(Objects.nonNull(leftResult)&&Objects.nonNull(rightResult))) return root;
- * //左右找到一个,即该子树仅存在p|q中一个,继续向上返回
- * else if(Objects.nonNull(leftResult)&&Objects.isNull(rightResult)) return leftResult;
- * else if(Objects.isNull(leftResult)&&Objects.nonNull(rightResult)) return rightResult;
- * //左右都没有找到,则说明该子树没有目标值,返回null
- * else return null;
- */
-
- }
不建议用迭代,理解太复杂,除非有要求。
这里需要两个栈,一个栈用来维护遍历树的操作。
另一个栈用来描述找到的节点在树种的位置关系,用来向上返回找到的值,且可以用来判断找到的两个节点是否在此处汇合。
eg: null null null 3 9 null 即可表示要找的值在同一层,一个null表示即将出现一个中间节点,两值汇合后的下一个null出现时对应的中间节点,即为汇合点,即最近公共祖先。
- //迭代
- public TreeNode lowestCommonAncestor2(TreeNode root, TreeNode p, TreeNode q) {
- //自定义栈-模拟递归
- Stack<TreeNode> stack=new Stack<>();
- //暂存找到的值,并指示层级
- Stack<TreeNode> resultStack=new Stack<>();
- stack.push(root);
- while(!stack.isEmpty()){
- TreeNode cur=stack.pop();
- if (Objects.nonNull(cur)) {
- //节点入栈
- stack.push(cur);
- stack.push(null);
- resultStack.push(null);//每加一个null相当于一层,用于只是层级
- //保证后序遍历的顺序入栈
- if(Objects.nonNull(cur.right)) stack.push(cur.right);
- if(Objects.nonNull(cur.left)) stack.push(cur.left);
- }else{
- //碰到中间节点
- cur=stack.pop();
- //该层有找到的值加入结果暂存层
- if(cur.val==p.val||cur.val==q.val){
- resultStack.push(cur);
- }
- TreeNode node=resultStack.pop();
- if(node!=null){//该层有找到的值
- if(resultStack.peek()!=null) return cur;//该层找到两个值
- else {
- resultStack.pop();//该层找到一个值,上移
- resultStack.push(node);
- }
- }
- }
- }
- return null;
- }
时间复杂度:
递归:O(n)
迭代:O(n)
空间复杂度:
递归:O(n)
迭代:O(2n)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。