问题
给定⼀个⼆叉树,找到最⻓的路径,这个路径中的每个节点具有相同数值。 这条路径可以经过也可以不经过根节点。 注意:两个节点之间的路径⻓度由它们之间的边数表示。
示例:
输入:
输出:最长路径的元素是5
其长度是3
分析
分析一下题目,其实就是要找一个二叉树内具有相同的值的节点的最长路径,我们可以从根节点开始,逐步往下遍历,寻找相同的值的节点的最长路径,因此,这道题是一个很明显的深度优先搜索DFS的题目。
DFS的题目需要用到递归的知识,因此我们考虑两个方面:终止条件和函数执行体。因为是深度优先搜索,所以很明显终止条件是搜索到叶子节点的时候就停止递归搜索。而如何进行写函数执行体,我们需要考虑两个方面,一个是两个节点的值是否相同,一个是两个节点是否连续。
这里要避开两个错误思路。
一个是判断两个节点的值是否相同的时候,只使用了一个变量去记录,如果相同就保持变量不变,记录下这个值是多少,如果不同就更新这个值。这个思路是错误的,因为你在DFS的时候,是先搜索完左子树,然后再回溯搜索右子树的,所以可能你根节点和左子树根节点值不同,但是和右子树根节点值相同,但是当你搜索到右子树的时候,那个变量的值已经被你搜索左子树的时候就更新掉了,就会判断不到两个节点值相同。
另一个是判断其根节点和左右孩子的值是否相同时,如果是用当前节点和其左右孩子去比他们的值是否相同,显然增加了代码量,且有悖于DFS的思想,极大增加了运行时间,会变成类似BFS搜索的样子,因此该题的正确思路应该是判断当前节点是否与其父节点的值相同。
除此之外,本题没有使用一个二维数组进行值的存放和当前值的连续路径长度,是因为递归过程需要多次判断值是否相同,相同后再对路径长度进行修改,即需要多次对二维数组的某一行进行操作,如果使用二维数组会增加运行时间。因此本代码使用了两个一维数组进行存储,同时因为题目没有设置二叉树节点值的最大值,如果值非常的大,那么数组的长度也会非常的大,所以本项目使用了动态数组进行存储,注意不能使用哈希表、图、二元组等数据结构进行存储,因为这些数据结构的值是无法修改的。
代码和运行结果
#include <bits/stdc++.h>
using namespace std;
typedef struct BinTree
{
int data;
BinTree* pleft;
BinTree* pright;
BinTree* parent;
}T;
int ans,lens;
vector<int> no;
vector<int> l;
T* CreateTree()
{
T* pa = (T*)malloc(sizeof(T));
T* pb = (T*)malloc(sizeof(T));
T* pc = (T*)malloc(sizeof(T));
T* pd = (T*)malloc(sizeof(T));
T* pe = (T*)malloc(sizeof(T));
T* pf = (T*)malloc(sizeof(T));
pa->data = 5;
pa->pright = pc;
pa->pleft = pb;
pb->data = 4;
pc->data = 5;
pb->pleft = pd;
pb->pright = pe;
pc->pleft = NULL;
pc->pright = pf;
pd->data = 1;
pe->data = 1;
pf->data = 5;
pd->pleft = NULL;
pd->pright = NULL;
pe->pleft = NULL;
pe->pright = NULL;
pf->pleft = NULL;
pf->pright = NULL;
pa->parent = NULL;
pb->parent = pa;
pc->parent = pa;
pd->parent = pb;
pe->parent = pb;
pf->parent = pc;
return pa;
}
void DFS(T* tree)
{
if (tree== NULL)
return;
if (tree->parent == NULL || tree->parent->data != tree->data) //不连续
{
no.push_back(tree->data);
l.push_back(1);
}
else//连续
{
int i;
for (i = no.size()-1;i >= 0;i--)
{
if (no[i] == tree->data)
break;
}
l[i]++;
}
DFS(tree->pleft);
DFS(tree->pright);
return;
}
int main()
{
T* ptop = CreateTree();
DFS(ptop);
ans = no[0];
lens = l[0];
for (int i = 1;i < no.size();i++)
{
if (l[i] > lens)
{
lens = l[i];
ans = no[i];
}
}
cout << "最长路径的元素是" << ans <<endl;
cout << "其长度是" << lens << endl;
return 0;
}
DFS的本质就是递归,所以考虑的事情就四个:是否需要返回值,是否需要回溯,递归终止条件是什么,函数执行体。本题是为了寻找同值最长路径,所以函数执行体就是判断两个节点是否同值以及是否连续;因为是二叉树的DFS,所以终止条件就是遍历到叶子节点的时候就停止递归;因为此题没有对二叉树进行任何的修改,所以也不需要回溯;本题只需要对每个节点进行判断操作,也不需要利用节点信息进行其他算术运算,所以也不需要返回值。以此就能写出本题代码。