二叉树相关题目
236. 二叉树的最近公共祖先
题目
二叉树的递归框架:
void traverse(TreeNode root) {
// 前序遍历
traverse(root.left)
// 中序遍历
traverse(root.right)
// 后序遍历
}
套入该题目给的函数:
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
TreeNode leftResult = lowestCommonAncestor(root.left,p,q);
TreeNode rightResult = lowestCommonAncestor(root.right,p,q);
}
然后对框架进行“添油加醋”,具体需要思考以下3个问题:
1、这个函数是干嘛的?
2、这个函数参数中的变量是什么?
3、得到函数的递归结果后,应该干什么?
现在对这3个问题一个一个进行回答。
1、这个函数是干嘛的?
给该函数输入三个参数root,p,q,它会返回一个节点。我们来定义一下具体的规则。
规则1:如果p、q都在以root为根的树中,返回p、q的最近公共祖先节点
规则2:如果p、q都不在以root为根的树中,返回null
规则3:
3.1如果只有p在以root为根的树中,而q不在,返回p
3.2如果只有q在以root为根的树中,而p不在,返回q
2、这个函数参数中的变量是什么?
p、q随着递归的进行并不会改变,发生改变的是root,因为会不断传入root.left和root.right
3、得到函数的递归结果后,应该干什么?
base case对传入的root进行讨论:
情况1:root为空,返回null
情况2:
2.1 root=q,若p在以root(q)为根节点的树中,则应返回root(q);若p不在以root(q)为根节点的树中,根据“规则3.2”,则应返回root(q)。即root=q时,返回root。
2.2 同理,root=p时,返回root。
对递归调用的结果leftResult、rightResult进行讨论:
情况1:
1.1 如果leftResult为null、rightResult不为null,说明p、q的最近公共祖先为rightResult,返回rightResult
1.2 如果leftResult不为null、rightResult为null,说明p、q的最近公共祖先为leftResult,返回leftResult
情况2:
如果leftResult、rightResult均为null,说明p、q既不在root的左子树中,也不在root的右子树中,没有公共祖先,返回null
情况3:
如果leftResult、rightResult均不为null,应该对应“规则3”,p在以leftResult为根的节点中,q在以rightResult为根的节点中,或者是q在以leftResult为根的节点中,p在以rightResult为根的节点中,总之就是p、q的最近公共祖先为root,返回root。
完整代码:
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
//base case,对root进行讨论
if(root == null){
return null;
}
if(root == p||root == q){
return root;
}
TreeNode leftResult = lowestCommonAncestor(root.left,p,q);
TreeNode rightResult = lowestCommonAncestor(root.right,p,q);
//对递归调用的结果进行讨论
if(leftResult == null && rightResult != null){
return rightResult;
}
if(leftResult != null && rightResult == null){
return leftResult;
}
if(leftResult == null && rightResult == null){
return null;
}
//if(leftResult != null && rightResult != null)
return root;
}
341. 扁平化嵌套列表迭代器
题目
先要读懂题目意思,这道题的题意较难理解,理解以下几个点:
- NestedInteger数据结构:题目给出的是个接口,给了3个抽象方法,实际的NestedInteger数据结构我们是可以脑补出来的。最后给出这个脑补的数据结构。
- 给出的3个函数:构造函数、next()、hasNext()
还要知道List集合的迭代器,通过iterator()方法获取迭代器,迭代器本身有next()、hasNext()方法,含义跟本题中要写的两个同名方法意义相同。
List<Integer> result = new LinkedList<>();
……
Iterator<Integer> it = result.iterator();
代码:
public class NestedIterator implements Iterator<Integer> {
//扁平化结果list的迭代器
Iterator<Integer> it = null;
//构造函数
public NestedIterator(List<NestedInteger> nestedList) {
//list存放扁平化后的结果
List<Integer> result = new LinkedList<>();
for(NestedInteger nI : nestedList){
traverse(nI,result);
}
this.it = result.iterator();
}
@Override
public Integer next() {
return it.next();
}
@Override
public boolean hasNext() {
return it.hasNext();
}
public void traverse(NestedInteger nI,List<Integer> result){
//是整数,添加进结果list
if(nI.isInteger()){
result.add(nI.getInteger());
return;
}
//是list,继续递归
for(NestedInteger nI_:nI.getList()){
traverse(nI_,result);
}
}
}
NestedInteger数据结构
public class NestedInteger {
private Integer val;
private List<NestedInteger> list;
public NestedInteger(Integer val) {
this.val = val;
this.list = null;
}
public NestedInteger(List<NestedInteger> list) {
this.list = list;
this.val = null;
}
// 如果其中存的是一个整数,则返回 true,否则返回 false
public boolean isInteger() {
return val != null;
}
// 如果其中存的是一个整数,则返回这个整数,否则返回 null
public Integer getInteger() {
return this.val;
}
// 如果其中存的是一个列表,则返回这个列表,否则返回 null
public List<NestedInteger> getList() {
return this.list;
}
}
NestedInteger数据结构与N叉树的相似性
[[1,1],2,[1,1]]这种结构,实际相当于是N叉树,可以看看两者的数据结构对比:
class NestedInteger {
Integer val;
List<NestedInteger> list;
}
/* 基本的 N 叉树节点 */
class TreeNode {
int val;
TreeNode[] children;
}

所以就可以使用N叉树的遍历框架:
void traverse(TreeNode root) {
for (TreeNode child : root.children)
traverse(child);
871

被折叠的 条评论
为什么被折叠?



