代码题(66)— 二叉树的所有路径、最长同值路径
1、257. 二叉树的所有路径
给定一个二叉树,返回所有从根节点到叶子节点的路径。
说明: 叶子节点是指没有子节点的节点。
示例:
输入: 1 / \ 2 3 \ 5 输出: ["1->2->5", "1->3"] 解释: 所有根节点到叶子节点的路径为: 1->2->5, 1->3
这道题给我们一个二叉树,让我们返回所有根到叶节点的路径,跟之前那道Path Sum II很类似,比那道稍微简单一些,不需要计算路径和,只需要无脑返回所有的路径即可,那么思路还是用递归来解,博主之前就强调过,玩树的题目,十有八九都是递归,而递归的核心就是不停的DFS到叶结点,然后在回溯回去。在递归函数中,当我们遇到叶结点的时候,即没有左右子结点,那么此时一条完整的路径已经形成了,我们加上当前的叶结点后存入结果res中,然后回溯。注意这里结果res需要reference,而out是不需要引用的,不然回溯回去还要删除新添加的结点,很麻烦。为了减少判断空结点的步骤,我们在调用递归函数之前都检验一下非空即可,代码而很简洁,参见如下:
/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode() : val(0), left(nullptr), right(nullptr) {} * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} * }; */ class Solution { public: vector<string> binaryTreePaths(TreeNode* root) { vector<string> res; if(root == nullptr) return res; string temp = ""; allPath(root, temp, res); return res; } void allPath(TreeNode* root, string temp, vector<string>& res){ if(!root->left && !root->right) res.push_back(temp+ to_string(root->val)); if(root->left) allPath(root->left, temp+to_string(root->val)+ "->", res); if(root->right) allPath(root->right, temp+to_string(root->val)+ "->", res); } };
2、687. 最长同值路径
给定一个二叉树,找到最长的路径,这个路径中的每个节点具有相同值。 这条路径可以经过也可以不经过根节点。
注意:两个节点之间的路径长度由它们之间的边数表示。
这道题让我们求最长的相同值路径,跟之前那道 Count Univalue Subtrees 十分的类似,解法也很类似。对于这种树的路径问题,递归是不二之选。在递归函数中,我们首先对其左右子结点调用递归函数,得到其左右子树的最大相同值路径长度,下面就要来看当前结点和其左右子结点之间的关系了,如果其左子结点存在且和当前节点值相同,则left自增1,否则left重置0;同理,如果其右子结点存在且和当前节点值相同,则right自增1,否则right重置0。然后用left+right来更新结果res。而调用当前节点值的函数只能返回left和right中的较大值,因为如果还要跟父节点组path,就只能在左右子节点中选一条path,当然选值大的那个了,什么意思呢,举个例子来说吧,比如下面的这棵二叉树:
1 / \ 4 5 / \ \ 4 4 5 / 4
若此时的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的话,那么回溯到根结点的时候,路径长度又可以增加了,参见代码如下:
/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode() : val(0), left(nullptr), right(nullptr) {} * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} * }; */ class Solution { public: int longestUnivaluePath(TreeNode* root) { if(root == nullptr) return 0; int res = 0; helper(root, res); return res; } int helper(TreeNode* root, int& res){ if(root == nullptr) return 0; int left = helper(root->left, res); int right = helper(root->right, res); left = (root->left && root->val == root->left->val) ? left+1 : 0; right = (root->right && root->val == root->right->val) ? right+1 : 0; res = max(res, left+right); return max(left, right); } };