题解 | #最长路径#

最长路径

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进行循环调用。
空间复杂度:。和方法一一样,创建了一个二维数组来存储路径和点的信息。

全部评论

相关推荐

不愿透露姓名的神秘牛友
09-30 19:49
起名星人:蛮离谱的,直接要求转投销售
投递汇川技术等公司10个岗位
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务