文章目录
剑指offer题解汇总 Java实现
https://blog.csdn.net/guliguliguliguli/article/details/126089434
本题链接
知识分类篇 - 树 - JZ86 在二叉树中找到两个节点的最近的公共祖先
题目
题目的主要信息
-
给出一棵树其中某一个结点指针
-
返回这棵树按照中序遍历的该节点的下一个顺序节点
-
树的每个节点都有三个指针,指向左子节点、右子节点、父节点
方案一 中序遍历递归
递归是一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解。因此递归过程,最重要的就是查看能不能将原本问题分解为更小的子问题,这是递归使用的关键。
而二叉树的递归,则是将某个节点的左子树、右子树看成一棵完整的树,那么对于子树的访问或者操作的子问题,因此可以自我调用函数不断进入子树。
思路
首先根据给定输入中的节点指向父级进行迭代,直到找到该树的根节点;然后进行中序遍历,当遍历到和给定树节点相同的节点时,下一个节点就是要返回的目标节点
具体做法
-
首先根据当前给出的节点找出根节点
-
从根节点开始中序遍历
-
将中序遍历的结果存储下来
-
最终拿当前节点匹配是否有符合要求的下一个节点
注意
中序遍历结束以后,arrayList中是按照中序遍历顺序存储的节点,在找到目标节点以后,只要返回它的下一个就好,我的代码是设置了一个flag,初始化为false,找到以后就会设置为true。在进入下一次循环,检查到flag为true,直接返回该节点即可。
代码一 设置flag标记
import java.util.*;
/*
public class TreeLinkNode {
int val;
TreeLinkNode left = null;
TreeLinkNode right = null;
TreeLinkNode next = null;
TreeLinkNode(int val) {
this.val = val;
}
}
*/
public class Solution {
private ArrayList<TreeLinkNode> inOrderNodes = new ArrayList<>();
public TreeLinkNode GetNext(TreeLinkNode pNode) {
TreeLinkNode targetNode = pNode;
while (pNode.next != null) {
pNode = pNode.next;
}
inOrderSearch(pNode);
boolean flag = false;
for (TreeLinkNode inOrderNode : inOrderNodes) {
if (flag) {
return inOrderNode;
}
if (inOrderNode.val == targetNode.val) {
flag = true;
}
}
return null;
}
private void inOrderSearch(TreeLinkNode pNode) {
if (pNode == null) {
return;
}
inOrderSearch(pNode.left);
inOrderNodes.add(pNode);
inOrderSearch(pNode.right);
}
}
代码二 获取整个arrayList的大小
官方给出的代码,是直接获取arrayList的大小,还有一个小细节,就是在for循环中,结束的条件并不是i<size
,而是i<size-1
,这样的处理是为了避免目标节点是中序遍历中的最后一个节点,这样该节点的下一个节点是null,通过arrayList.get(i+1)会出错(细节满分)
对于没有找到的,会在for循环结束以后,返回null
修改的代码
int size = inOrderNodes.size();
for (int i = 0; i < size - 1; i++) {
if (inOrderNodes.get(i) == targetNode) {
return inOrderNodes.get(i + 1);
}
}
return null;
完整的代码
import java.util.*;
/*
public class TreeLinkNode {
int val;
TreeLinkNode left = null;
TreeLinkNode right = null;
TreeLinkNode next = null;
TreeLinkNode(int val) {
this.val = val;
}
}
*/
public class Solution {
private ArrayList<TreeLinkNode> inOrderNodes = new ArrayList<>();
public TreeLinkNode GetNext(TreeLinkNode pNode) {
TreeLinkNode targetNode = pNode;
while (pNode.next != null) {
pNode = pNode.next;
}
inOrderSearch(pNode);
int size = inOrderNodes.size();
for (int i = 0; i < size - 1; i++) {
if (inOrderNodes.get(i) == targetNode) {
return inOrderNodes.get(i + 1);
}
}
return null;
}
private void inOrderSearch(TreeLinkNode pNode) {
if (pNode == null) {
return;
}
inOrderSearch(pNode.left);
inOrderNodes.add(pNode);
inOrderSearch(pNode.right);
}
}
方案二 分类直接寻找(分情况讨论)
思路
- 如果给出的节点有右子节点,则最终要返回的下一个节点即右子树的最左下的节点
注意不是该节点的右节点,因为可能会出现右节点又是一棵子树的情况,所以要不断深入到右子树最左下的节点
-
如果给出的节点无右子节点
-
判断该节点是否有父节点
-
没有父节点
- 则该节点就是中序遍历的最后一个节点,返回null
-
有父节点
-
且是当前节点是其父节点的左子节点,则返回其父节点
-
且是当前节点是其父节点的右子节点,则先要沿着左上方父节点爬树,一直爬到当前节点是其父节点的左子节点为止,返回的就是这个父节点;如果没有满足条件的节点,则返回NULL
-
-
-
代码(版本一)
根据上面的思路,写的代码
import java.util.*;
/*
public class TreeLinkNode {
int val;
TreeLinkNode left = null;
TreeLinkNode right = null;
TreeLinkNode next = null;
TreeLinkNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public TreeLinkNode GetNext(TreeLinkNode pNode) {
//有右子节点
if (pNode.right != null) {
pNode = pNode.right;
while (pNode.left != null) {
pNode = pNode.left;
}
return pNode;
} else {
//无右子节点
//判断是否有父节点
//没有父节点,也没有右子节点
if (pNode.next == null) {
return null;
} else {
//有父节点
//判断是否是其父节点的左子节点
if (pNode.next.left == pNode) {
return pNode.next;
} else {
//不是该父节点的左子节点,即是该父节点的右子节点
while (pNode.next != null && pNode.next.left != pNode) {
pNode = pNode.next;
}
if (pNode.next == null) {
return null;
}
return pNode.next;
}
}
}
}
}
代码(版本二)
根绝官方给的代码,把上面的代码修改了一下,更简洁一些
import java.util.*;
public class Solution {
public TreeLinkNode GetNext(TreeLinkNode pNode) {
// 情况一
if (pNode.right != null) {
pNode = pNode.right;
// 一直找到右子树的最左下的结点为返回值
while (pNode.left != null) {
pNode = pNode.left;
}
return pNode;
}
// 情况二
//该节点的父节点不为空,且该节点是父节点的左子节点
if (pNode.next != null && pNode.next.left == pNode) {
return pNode.next;
}
// 情况三
//该节点的父节点不为空,且该节点是父节点的右子节点
// 沿着左上一直爬树,爬到当前结点是其父节点的左自己结点为止
while (pNode.next != null && pNode.next.left != pNode) {
pNode = pNode.next;
}
if (pNode.next == null) {
return null;
}
return pNode.next;
}
}