题目描述:
解法:深度优先遍历
思路:
采用深度优先遍历的方式,我们可以从顶向下访问到所有节点。并且遍历下一个子节点时,我们也能够知道子节点是属于父节点的左子树,还是右子树。
所以我们可以为每个节点缓存两个值,一个l表示到达当前节点时,该节点为左子树时的路径数,一个r表示该节点为右子树时的到达路径。 当然,一个节点要么是左子树,要么是右子树,所以l和r其中只有一个有值。
那么在遍历该节点的子节点时,如果子节点是左子树,那么它的l值就是父节点的r值加1. 如果是右子树,就是父节点的l值加1.
参考来源:
作者:林晓东
链接:https://leetcode.cn/problems/longest-zigzag-path-in-a-binary-tree/solutions/913653/dfsduan-duan-ba-xing-dai-ma-you-ya-jie-j-kfyz/
代码解析:
函数longestZigZag
是入口函数,通过调用visit
函数从根节点开始访问,并将初始的左子树最大长度和右子树最大长度都设为0。最后返回最长的zigzag路径长度。
在visit
函数中,首先更新最大长度max
,取左子树最大长度leftMax
和右子树最大长度rightMax
的较大值。然后判断当前节点是否为空,如果为空,则结束访问。接着访问左子树,如果左子树存在,以当前节点作为右拐点,继续向右子树方向访问,即visit(root.left, rightMax + 1, 0)
,左子树最大长度加1,右子树最大长度重置为0。然后访问右子树,如果右子树存在,以当前节点作为左拐点,继续向左子树方向访问,即visit(root.right, 0, leftMax + 1)
,右子树最大长度加1,左子树最大长度重置为0。
private int max = 0;
public int longestZigZag(TreeNode root) {
// 从根节点开始访问,初始的左右子树最大长度都为0
visit(root, 0, 0);
// 返回最长的zigzag路径长度
return max;
}
private void visit(TreeNode root, int leftMax, int rightMax) {
// 更新最大长度,取左右子树最大长度的较大值
max = Math.max(max, Math.max(leftMax, rightMax));
// 如果当前节点为空,结束访问
if (root == null) {
return;
}
// 访问左子树
if (root.left != null) {
// 在左子树中,以当前节点作为右拐点,继续向右子树方向访问,左子树最大长度加1,右子树最大长度重置为0
visit(root.left, rightMax + 1, 0);
}
// 访问右子树
if (root.right != null) {
// 在右子树中,以当前节点作为左拐点,继续向左子树方向访问,右子树最大长度加1,左子树最大长度重置为0
visit(root.right, 0, leftMax + 1);
}
/*
* 上面为什么往左拐是rightMax + 1,右拐leftMax + 1?
* 首先,往那边拐,对应的函数参数位置+1这个好理解
* 现在讲解左拐是rightMax + 1,因为你现在是左拐了对吧
* 然后题目是交叉长度,所以你左拐的长度就得是上一个的右拐的长度,
* 也就是等同于当前rightMax ,再去+ 1
* 右拐也同理
* 每拐一次,也就是每执行一次visit函数,max赋值左大和右大之间的最大值
* */
}
难点:
* 上面为什么往左拐是rightMax + 1,右拐leftMax + 1? * 首先,往那边拐,对应的函数参数位置+1这个好理解 * 现在讲解左拐是rightMax + 1,因为你现在是左拐了对吧 * 然后题目是交叉长度,所以你左拐的长度就得是上一个的右拐的长度, * 也就是等同于当前rightMax ,再去+ 1 * 右拐也同理 * 每拐一次,也就是每执行一次visit函数,max赋值左大和右大之间的最大值