最长同值路径(力扣第687题)
题目:
给定一个二叉树,找到最长的路径,这个路径中的每个节点具有相同值。 这条路径可以经过也可以不经过根节点。
注意:
两个节点之间的路径长度由它们之间的边数表示。
示例:
输入:
5 / \ 4 5 / \ \ 1 1 5
输出:2
输入:
1 / \ 4 5 / \ \ 4 4 5
输出:2
分析:
结果路径要求既是最长的,同时路径中的值也都是相同的值,这是两个限制条件。同时路径可以不经过根节点,也可以经过根节点。那么我们来具体的分析:
分析可以知道,最终的结果可能经过根结点也可能不经过根结点。由于我们要求的是最长的路径长度,所以给定的二叉树中就可能涉及多个拥有相同值的路径,需要计算这些路径的长度,然后求出最终的最大值。由于路径有多个,值也有多个,所以求最大值可以通过定义一个成员变量,以记录当前最大值的方式记录最长路径长度。而计算结果路径要从两个维度去考虑:一个是横向,即计算以当前结点为父结点的某个子树的最长路径长度,作为一种局部的结果,去和那个记录最终结果的成员变量去比较,记录二者的最大值;一种是纵向,因为以当前某个结点为父结点的局部最长路径不一定是最终的结果,还要考虑整体的结果,即纵向向上延伸。向上延伸的时候,就需要从当前这个子树中选出一个纵向的最长长度,即子树的最长结果路径+1作为这个子树向上延伸时的结果长度。
横向计算时,就从某个结点进行分析,以该结点为父亲结点的子树中结果路径主要包括,两种:第一种是最长路径从左子树的某个叶子结点一直路过根结点到右子树的某个叶子结点;第二种是结果路径从根结点到某一棵子树的叶子结点,结果路径不涉及另一棵子树。最终的结果值也分为两个部分,即left和right,如果这个结点和其左右子结点都不相同,那么left = 0,right = 0;当前这个局部的结果就为0,如果某一个子结点和当前结点的值不相同,那么就将对应部分的值置为0。最终的局部结果就是left+right,然后去和成员变量比较。
纵向计算是为了将某个局部结果作为一个更大的子树的某个小子树去计算,即为了参与一个更大的横向计算;横向计算是作为一种计算结果,它是局部的,它可能是最终的结果,也可能不是,但一定是多个的,横向计算多少次就说明有多少种情况。至于为何父结点和子结点值不同,就将对应部分的长度置为0,是因为值不同,已经无法在当前这个局部范围内构成相同值路径了,同时也不可能和更上一层的结点构成相同值路径了(因为不连续)。
代码:
private int maxPath = 0; public int longestUnivaluePath(TreeNode root) { if (root == null){ return 0; } lengthLongPath(root); return maxPath; } private int lengthLongPath(TreeNode root){ if (root == null){ return 0; } int left = 0; int right = 0; int leftChild = lengthLongPath(root.left); int rightChild = lengthLongPath(root.right); if (root.left != null && root.val == root.left.val){ left = leftChild + 1; }else { left = 0; } if (root.right != null && root.val == root.right.val){ right = rightChild + 1; }else { right = 0; } maxPath = Math.max(maxPath,left + right); return Math.max(right,left); }