目录:
# 一、题目介绍
# 二、解题分析
# 三、解题思路
一、题目介绍
给定二叉树的根节点 root
,找出存在于 不同 节点 A
和 B
之间的最大值 V
,其中 V = |A.val - B.val|
,且 A
是 B
的祖先。
(如果 A 的任何子节点之一为 B,或者 A 的任何子节点是 B 的祖先,那么我们认为 A 是 B 的祖先)
示例 1:
输入:root = [8,3,10,1,6,null,14,null,null,4,7,13] 输出:7 解释: 我们有大量的节点与其祖先的差值,其中一些如下: |8 - 3| = 5 |3 - 7| = 4 |8 - 1| = 7 |10 - 13| = 3 在所有可能的差值中,最大值 7 由 |8 - 1| = 7 得出。
示例 2:
输入:root = [1,null,2,null,0,3] 输出:3
二、解题分析
题目要求输出的是每个祖先节点和子孙节点的数值差值最大,因而在遍历每一段由根节点到没有子节点的尾节点时需要不断获取最大数值和最小数值,每次遍历到一个尾节点时就要计算一次差值,则需要有一个回溯的操作,我这里用栈pop()方法来实现回溯的操作
三、解题思路
代码先奉上
public int maxAncestorDiff(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
Stack<int []> prevData = new Stack<>();//用来存储前一个节点对应的最小值和最大值
int ans = 0;
TreeNode nod = root;
stack.push(nod);
int min = nod.val,max = nod.val;
while(!stack.isEmpty()) {
if(nod.left == null && nod.right == null) {
ans = Math.max(ans, max - min);//获取最大的差值
stack.pop();
if(stack.isEmpty())
break;
else
nod = stack.peek();
if(prevData.peek() != null) {
min = prevData.peek()[0];
max = prevData.peek()[1];
prevData.pop();
}
}
//先将根节点从栈中取出,后以二叉树前序遍历的方式存放数据
if(nod.left != null || nod.right != null)
nod = stack.pop();
if(min >= nod.val)
min = nod.val;
if(max <= nod.val)
max = nod.val;
if(nod.left != null && nod.right != null)//当节点的左右节点都存在时才执行
prevData.push(new int[] {min,max});//把前面的最小值和最大值压入栈中
if(nod.right != null)
stack.push(nod.right);
if(nod.left != null) {
stack.push(nod.left);
nod = nod.left;
}else if(nod.right != null)
nod = stack.peek();
if(min >= nod.val)
min = nod.val;
if(max <= nod.val)
max = nod.val;
}
return ans;
}
(1)首先创建两个栈分别用来存放左右子节点和当前节点对应那段的最小数最大数,并将root压入栈stack中,初始化结果ans用于存放每次计算最大数和最小数差值得到的最大差值;
(2)接着①添加一个回溯操作,当当前节点没有左右子节点(即为尾节点)时,计算一次当前段的最大数和最小数的差值,并存放在变量ans中,将尾节点从栈stack中pop出去。②然后有一步重要的操作是判断栈中是否为空,为空就break掉(如下图所示,因为我接下来要每次遍历一个节点的字节点时,要把当前节点从栈stack中pop出去,则当当前节点为最后一个尾节点时,就不能再执行下面的代码,直接break掉)
,不为空就将当前节点赋值为栈stack中存放在顶部的节点。③接下来将栈prevData中存放的前一个尾节点的带有左右节点的祖先节点对应的最小最大数值赋予变量min和max,并对prevData进行pop操作(如下图,当遍历到尾节点3时,pop掉stack中的节点3,并将节点0对应的最小最大数值赋值给min和max,才能接下遍历节点4,而min和max不会使用节点0、1、2、3这段的min和max)
(3)接着判断当前指针的左右指针是否为空,不为空才能将将当前指针赋值为stack的顶部存放的节点,并将顶部节点pop出去(这里的原因如下图所示,当当前节点为节点6时就会进入回溯操作,此时会将节点6pop出去((2)①中的操作),之后就会将节点3pop出去((3)的操作),而节点3又是一个尾节点,则又要进行回溯操作,可此时回溯中pop栈中的节点是节点4,此时就出问题了。而代码中需要实现的是尾节点只在回溯操作中pop)
(4)接着更新min和max的值,并若当前节点有左右节点时,将此时的min和max压入栈prevData中
(5)按照二叉树的前序遍历先将右指针压入栈stack中(有右指针)并将左指针压入栈中(有左指针),并将nod赋值为nod.left。当没左指针有右指针时,将nod赋值为nod.right。
最后补上更新min和max的值