Given a binary tree, find the length of the longest path where each node in the path has the same value. This path may or may not pass through the root.

Note: The length of path between two nodes is represented by the number of edges between them.

Example 1:

Input:

              5
/ \
4 5
/ \ \
1 1 5

Output:

2

Example 2:

Input:

              1
/ \
4 5
/ \ \
4 4 5

Output:

2

Note: The given binary tree has not more than 10000 nodes. The height of the tree is not more than 1000.

这道题让我们求最长的相同值路径,跟之前那道 Count Univalue Subtrees 十分的类似,解法也很类似。对于这种树的路径问题,递归是不二之选。在递归函数中,我们首先对其左右子结点调用递归函数,得到其左右子树的最大相同值路径长度,下面就要来看当前结点和其左右子结点之间的关系了,如果其左子结点存在且和当前节点值相同,则left自增1,否则left重置0;同理,如果其右子结点存在且和当前节点值相同,则right自增1,否则right重置0。然后用left+right来更新结果res。而调用当前节点值的函数只能返回left和right中的较大值,因为如果还要跟父节点组path,就只能在左右子节点中选一条path,当然选值大的那个了,什么意思呢,举个例子来说吧,比如下面的这棵二叉树:

     / \

   / \   \

 /

若此时的node是只有两个结点的第二层的那个结点4,那么分别对其左右子结点调用递归,会得到 left = 1, right = 0,因为此时要跟结点4组成path,所以肯定挑左子结点(有两个4的那条边),那你会问为啥不能连上右子结点的那个4,这整条长度为3的path(left+right,此时的left和right已经分别自增1了,left=2,right=1)其实我们已经用来更新过结果res了。需要注意的是我们的递归函数helper返回值的意义,并不是经过某个结点的最长路径的长度,最长路径长度保存在了结果res中,不是返回值,返回的是以该结点为终点的最长路径长度,这样回溯的时候,我们还可以继续连上其父结点,比如若根结点也是4的话,那么回溯到根结点的时候,路径长度又可以增加了,参见代码如下:

解法一:

class Solution {
public:
int longestUnivaluePath(TreeNode* root) {
int res = ;
helper(root, res);
return res;
}
int helper(TreeNode* node, int& res) {
if (!node) return ;
int left = helper(node->left, res);
int right = helper(node->right, res);
left = (node->left && node->val == node->left->val) ? left + : ;
right = (node->right && node->val == node->right->val) ? right + : ;
res = max(res, left + right);
return max(left, right);
}
};

下面这种解法跟上面的方法很类似,区别在于递归函数中多了一个参数,parent保存的是父结点值,其实仔细比较下两种解法,发现就是加1的地方略有不同,那么这里helper的返回值意义就发生了变化,这里的返回值表示的是以当前结点的父结点为路径终点的最大相同值路径长度,这样我们递归出来的left和right就不用再加1,直接可以求和并更新结果res了,由于当前结点的父结点值知道,那么我们和父结点值比较一下,如果相同,返回left和right中较大值并再加1,如果不同,则返回0,这是因为之前说的必须要以父结点为路径终点,那么既然父结点的值不同,所以长度肯定是0了,参见代码如下:

解法二:

class Solution {
public:
int longestUnivaluePath(TreeNode* root) {
int res = ;
if (root) helper(root, root->val, res);
return res;
}
int helper(TreeNode* node, int parent, int& res) {
if (!node) return ;
int left = helper(node->left, node->val, res);
int right = helper(node->right, node->val, res);
res = max(res, left + right);
if (node->val == parent) return max(left, right) + ;
return ;
}
};

下面这种解法使用了两个递归函数,使得写法更加简洁了,首先还是先判断root是否为空,是的话返回0。然后对左右子节点分别调用当前函数,取其中较大值保存到变量sub中,表示左右子树中最长的相同值路径,然后就是要跟当前树的最长相同值路径比较,计算方法是对左右子结点调用一个helper函数,并把当前结点值传进去,把返回值加起来和sub比较,取较大值返回。顺便提一下,这里的helper函数的返回值的意义跟解法二中的是一样的。在helper函数里,若当前结点为空,或者当前节点值不等于父结点值的话,返回0。否则结返回对左右子结点分别调用helper递归函数中的较大值加1,我们发现这种写法跟求树的最大深度很像,参见代码如下:

解法三:

class Solution {
public:
int longestUnivaluePath(TreeNode* root) {
if (!root) return ;
int sub = max(longestUnivaluePath(root->left), longestUnivaluePath(root->right));
return max(sub, helper(root->left, root->val) + helper(root->right, root->val));
}
int helper(TreeNode* node, int parent) {
if (!node || node->val != parent) return ;
return + max(helper(node->left, node->val), helper(node->right, node->val));
}
};

类似题目:

Binary Tree Maximum Path Sum

Count Univalue Subtrees

Path Sum III

参考资料:

https://leetcode.com/problems/longest-univalue-path/

https://leetcode.com/problems/longest-univalue-path/discuss/108136/JavaC%2B%2B-Clean-Code

https://leetcode.com/problems/longest-univalue-path/discuss/108175/java-solution-with-global-variable

https://leetcode.com/problems/longest-univalue-path/discuss/108146/Concise-DFS-solution-with-no-global-variables

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Longest Univalue Path 最长相同值路径的更多相关文章

  1. [LeetCode] 687. Longest Univalue Path 最长唯一值路径

    Given a binary tree, find the length of the longest path where each node in the path has the same va ...

  2. LeetCode 687. Longest Univalue Path 最长同值路径 (C++/Java)

    题目: Given a binary tree, find the length of the longest path where each node in the path has the sam ...

  3. Leetcode687.Longest Univalue Path最长同值路径

    给定一个二叉树,找到最长的路径,这个路径中的每个节点具有相同值. 这条路径可以经过也可以不经过根节点. 注意:两个节点之间的路径长度由它们之间的边数表示. 示例 1: 输入: 5 / \ 4 5 / ...

  4. 【LeetCode】687. Longest Univalue Path 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 DFS 日期 题目地址:https://leetco ...

  5. 【Leetcode_easy】687. Longest Univalue Path

    problem 687. Longest Univalue Path 参考 1. Leetcode_easy_687. Longest Univalue Path; 2. Grandyang; 完

  6. LC 687. Longest Univalue Path

    Given a binary tree, find the length of the longest path where each node in the path has the same va ...

  7. LeetCode算法题-Longest Univalue Path(Java实现)

    这是悦乐书的第290次更新,第308篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第158题(顺位题号是687).给定二叉树,找到路径中每个节点具有相同值的最长路径的长度 ...

  8. [LeetCode] Longest Increasing Path in a Matrix 矩阵中的最长递增路径

    Given an integer matrix, find the length of the longest increasing path. From each cell, you can eit ...

  9. LeetCode Longest Increasing Path in a Matrix

    原题链接在这里:https://leetcode.com/problems/longest-increasing-path-in-a-matrix/ Given an integer matrix, ...

随机推荐

  1. java基础笔记(6)----面向对象的三大特性

    简介:面向对象的三大特性就是封装,继承,多态,是面向对象的核心. 封装 简介:封装是类的边界,可以对数据起到保护作用 特性:属性私有,提供公开的get/set方法 属性私有:private 数据类型 ...

  2. [LTR] 信息检索评价指标(RP/MAP/DCG/NDCG/RR/ERR)

    一.RP R(recall)表示召回率.查全率,指查询返回结果中相关文档占所有相关文档的比例:P(precision)表示准确率.精度,指查询返回结果中相关文档占所有查询结果文档的比例: 则 PR 曲 ...

  3. python内置函数 divmod()

    先来看一下builtins.py中的代码: def divmod(x, y): # known case of builtins.divmod """ Return th ...

  4. JavaEE HttpServlet 解析

    上一篇 文章中有提到,GenericServlet 是对 Servlet 的一个通用实现,并提供了一个抽象的 service() 方法.而我们的互联网是使用 Http 协议来通信的,那针对这个&quo ...

  5. C语言程序设计(基础)- 第2周作业

    1.阅读提问的智慧,要求仔细阅读链接内容,用自己的话描述你的收获,并举例子说明应该如何提问. 2.所有同学请在自己电脑上配置git.编译器(win10 系统的话就Dev-C++).翻译软件,十一回校后 ...

  6. 20162311 实验三 敏捷开发与XP实践 实验报告

    20162311 实验三 敏捷开发与XP实践 实验报告 实验内容 一.研究学习IDEA中的Code菜单 使用Code ->Reformate Code功能将以下代码格式化 public clas ...

  7. Beta阶段总结分析报告

    1 讨论照片 2 Postmortem结果 二手交易平台项目Postmortem结果 整理:程环宇 设想和目标 1.       我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有 ...

  8. Argparse简易教程

    Argparse简易教程 原文:Argparse Tutorial 译者:likebeta 本教程是对于Python标准库中推荐使用的命令行解析模块argparse的简单介绍. PS:还有其他两个模块 ...

  9. netty : NioEventLoopGroup 源码分析

    NioEventLoopGroup 源码分析 1. 在阅读源码时做了一定的注释,并且做了一些测试分析源码内的执行流程,由于博客篇幅有限.为了方便 IDE 查看.跟踪.调试 代码,所以在 github ...

  10. keycloak管理用户权限

    一.在keycloak中定义基础数据 1.realm 如果多个模块使用不同的用户权限,就分realm 如果多个模块共用一套用户权限,就顶一个一个realm 2.每个模块是一个client-app 3. ...