题解 | #最长路径#
最长路径
http://www.nowcoder.com/practice/430ded6b482d4d8bbcf2eca6f20e62e3
题意理解
n个房子对应于n个结点,街道就对应于结点之间的边,构成一张连通图。找到这张图中哪两点之间边上的数值之和最大。
方法一
深度优先搜索
使用二维数组path存储路径的信息,对于每一个点,要记录它和其它结点所有路径的长度。然后以每一个点分别作为起点,都进行一次深度优先搜索,每走一步都更新一次最长路径ans,注意这里的ans不需要退回。
示意图如下,最终答案对应的路径是1-5-2-3这一条路径的长度:
具体代码如下:
class Solution { public: /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * 返回最终结果 * @param n int整型 城市数量 * @param u int整型vector * @param v int整型vector * @param w int整型vector * @return long长整型 */ vector<pair<int, int>> path[100000]; long long ans=0; //x表示这一步的起点,pre表示上一步的起点 void dfs(int x, int pre, long long sum) { for (int i=0;i<path[x].size();i++) { //不能往回走 if (path[x][i].first==pre) continue; //不断更新ans ans = max(sum + path[x][i].second, ans); dfs(path[x][i].first, x, sum+path[x][i].second); } } long long solve(int n, vector<int>& u, vector<int>& v, vector<int>& w) { //path每个位置记录该点与其它点存在的连边 for (int i=0;i<n-1;i++) { path[u[i]].push_back({v[i],w[i]}); path[v[i]].push_back({u[i],w[i]}); } //对每个结点作为起始点进行dfs for (int i=1;i<=n;i++) { if (path[i].size()==1) { dfs(i,i,0); } } return ans; } };
时间复杂度:。每一个点作为起点遍历了一遍整个点集,是的时间,n个点总共是。
空间复杂度:。创建了一个二维数组来存储路径和点的信息。
方法二
对于一条路径,我们可以把它看成两条路径在同一结点处的拼接,以该点为连接点。所以,我们在递归的时候,不断更新维护每一个点的某两个子树child_i,child_j中最长路径相加得到的最大值。
同时,我们不需要考虑来时路径所在的子树child_v,因为如果以结点u为拼接点的最长路径来自于child_v和某个child_i,则这种情况会在以v为拼接点时考虑进去。
最重要的一点,在每一层的中,我们遍历当前拼接点x的path[x]之后,就已经完成了对x点所以情况的搜索,这与方法一是不一样的,方法一只是完成了以某个特定点为起点,经过x的路径的搜索。这导致我们在主程序中不需要循环调用dfs。
例如在方法一的图中,以5为例,它有4子树,以5为拼接点的最长路径可能是其中某两个子树的拼接。
具体代码如下:
class Solution { public: /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * 返回最终结果 * @param n int整型 城市数量 * @param u int整型vector * @param v int整型vector * @param w int整型vector * @return long长整型 */ vector<pair<int, int>> path[100000]; long long ans=0; //x表示这一步的起点,pre表示上一步的起点 long long dfs(int x, int pre){ long long child1 = 0; for(int i=0;i<path[x].size();i++){ if(path[x][i].first != pre){ long long child2 = dfs(path[x][i].first, x) + path[x][i].second; //更新ans ans = max(ans, child1+child2); //保留更长的子树中的路径 child1 = max(child1, child2); } } return child1; } long long solve(int n, vector<int>& u, vector<int>& v, vector<int>& w) { //path每个位置记录该点与其它点存在的连边 for (int i=0;i<n-1;i++) { path[u[i]].push_back({v[i],w[i]}); path[v[i]].push_back({u[i],w[i]}); } //选择任意一个点开始 dfs(1, 0); return ans; } };
时间复杂度:。仅仅在递归过程中遍历了一遍所有的点,主程序中没有对dfs进行循环调用。
空间复杂度:。和方法一一样,创建了一个二维数组来存储路径和点的信息。