lintcode 树上最长距离

lintcode 树上最长距离

描述

给出由n个结点,n-1条边组成的一棵树。求这棵树中距离最远的两个结点之间的距离。
给出三个大小为n-1的数组starts,ends,lens,表示第i条边是从starts[i]连向ends[i],长度为lens[i]的无向边。

返回的是树上任意两个结点的最远距离,而不是树的深度,注意给定的边是无向边。
题目保证给出的边一定能构成一棵树。

1≤n≤1∗10^5

​​
1≤lens[i]≤1∗10^3

样例

给出n=5,starts=[0,0,2,2],ends=[1,2,3,4],lens=[1,2,5,6],返回11。

解释:
(3→2→4)这条路径长度为11,当然(4→2→3)也是一样的。
给出n=5,starts=[0,0,2,2],ends=[1,2,3,4],lens=[5,2,5,6],返回13。

解释:
(1→0→2→4)这条路径长度为13,当然(4→2→0→1)也是一样的。

​​

思路

最一开始想到的暴力解法,直接维护一个二维数组,求出所有点之间的距离,找出最大值。但是发现n最大是10^5,时间复杂度只能是O(n),也就是说,在有限的遍历中就能找出那个最大值。因此需要知道一个树中的性质。
从a点找出一个最远点b,从b再出发,找出最远点c(很容易知道bc的距离是大于等于ab的,c点就是a点时取等号,a在bc这条路上的时候取大于号)那么bc就是最大距离。证明如下:
假设存在一条边的距离大于bc,那么首先,这条边的起点和终点绝对不是a或b或c,设为mn。
假设m与a是相通的,那么m,n,a之间不可能构成环,所以只有2种情况。此时a->m->n或者m->n->a的距离就大于m->n,不正确。也有可能是m->a->n 或者n->a->m这条路线,如果是这样的话。因为an和am这两条路的大小都小于ab(ab为a引出去的最长距离),所以ab,ac,am,an的大小关系就是
ab > an > ac 并且 ab > am > ac 并且 am+an > ab+ac,但是此时 b引出去的最长距离就不是b->a->c(此处有个问题,b引出的最长距离未必经过a,可以是另外一条支路,也就是abc公用了一个根,此时把根理解为a,一样得出结论)就是b->a->n或者m,又不正确。
因此证明了bc这条边就是最长的距离。

本人表达能力和逻辑能力欠佳,所以可以参考这位大佬的
https://blog.csdn.net/macuilxochitl/article/details/19157579

代码

我写的代码维护了一个n^2大小的矩阵,导致了内存超出了限制。。
因为已经纠结这题很久了,就没有再去想解决的方法。

这是我的代码

class Solution {
public:
    /**
     * @param n: The number of nodes
     * @param starts: One point of the edge
     * @param ends: Another point of the edge
     * @param lens: The length of the edge
     * @return: Return the length of longest path on the tree.
     */
    
    void dfs(vector<vector<int>> cost,const int tar, int & _max, int & END) {
        int n = cost.size(),top = -1, j, s[10007];
	    vector<int> visited(n, 0);
        visited[tar] = 1;
	    s[++top] = tar;
    	int v;
    	while (top != -1) {
    	    v = s[top];
    	    for (j = 0; j < n; j++) {
    	        if (visited[j] == 0 && cost[v][j] != 0) {
    	            visited[j] = 1;
    	            s[++top] = j;
    	            if (cost[tar][j] == 0) {
    	                cost[j][tar] = cost[tar][j] = cost[tar][v] + cost[v][j];
    	                if (_max < cost[tar][j]) {
    	                    _max = cost[tar][j];
    	                    END = j;
    	                }
    	            }
    	            break;
    	        }
    	    }
    	    if (j == n)
    	        top--;
    	}
    }

    
    int longestPath(int n, vector<int> &starts, vector<int> &ends, vector<int> &lens) {
        // Write your code here
        vector<vector<int>> cost;
        cost.resize(n);
        for (int i = 0; i < n; i++)
            cost[i].resize(n);
        for (int i = 0; i < n-1; i++) {
            int start = starts[i], 
                end = ends[i], 
                len = lens[i];
            cost[start][end] = len;
            cost[end][start] = len;
        }
        int _max = 0, END = 0;
        dfs(cost, 0,_max, END);
        _max = 0;
        dfs(cost, END,_max, END);
        return _max;
    }
};

这个是九章算法种提供的答案。
原网址:
https://www.jiuzhang.com/solution/longest-path-on-the-tree/#tag-other

/**
* 本参考程序来自九章算法,由 @P同学 提供。版权所有,转发请注明出处。
* - 九章算法致力于帮助更多中国人找到好的工作,教师团队均来自硅谷和国内的一线大公司在职工程师。
* - 现有的面试培训课程包括:九章算法班,系统设计班,算法强化班,Java入门与基础算法班,Android 项目实战班,
* - Big Data 项目实战班,算法面试高频题班, 动态规划专题班
* - 更多详情请见官方网站:http://www.jiuzhang.com/?source=code
*/ 

public class Solution {
    /**
     * @param n: The number of nodes
     * @param starts: One point of the edge
     * @param ends: Another point of the edge
     * @param lens: The length of the edge
     * @return: Return the length of longest path on the tree.
     */
    class TreeNode {
        int val;
        Map<TreeNode, Integer> neighbors;
        
        public TreeNode(int val) {
            this.val = val;
            neighbors = new HashMap<>();
        }
    }
    
    class Pair implements Comparable<Pair> {
        TreeNode node;
        int val;
        
        public Pair(TreeNode node, int val) {
            this.node = node;
            this.val = val;
        }
        
        @Override
        public int compareTo(Pair other) {
            return this.val - other.val;
        }
    }
    
    public int longestPath(int n, int[] starts, int[] ends, int[] lens) {
        if (n <= 1) {
            return 0;
        }
        
        Map<Integer, TreeNode> map = new HashMap<>();
        for (int i = 0; i < starts.length; i++) {
            if (!map.containsKey(starts[i])) {
                TreeNode newNode = new TreeNode(starts[i]);
                map.put(starts[i], newNode);
            }
            if (!map.containsKey(ends[i])) {
                TreeNode newNode = new TreeNode(ends[i]);
                map.put(ends[i], newNode);
            }
            TreeNode node1 = map.get(starts[i]);
            TreeNode node2 = map.get(ends[i]);
            node1.neighbors.put(node2, lens[i]);
            node2.neighbors.put(node1, lens[i]);
        }
        TreeNode root = map.get(0);
        
        Pair p = bfsHelper(n, root);
        return bfsHelper(n, p.node).val;
    }
    
    private Pair bfsHelper(int n, TreeNode node) {
        Pair res = new Pair(null, -1);
        boolean[] visited = new boolean[n];
        visited[node.val] = true;
        
        PriorityQueue<Pair> pq = new PriorityQueue<>();
        pq.offer(new Pair(node, 0));
        
        while (!pq.isEmpty()) {
            Pair curt = pq.poll();
            res = curt;
            for (Map.Entry<TreeNode, Integer> entry : curt.node.neighbors.entrySet()) {
                if (visited[entry.getKey().val]) {
                    continue;
                }
                visited[entry.getKey().val] = true;
                pq.offer(new Pair(entry.getKey(), curt.val + entry.getValue()));
            }
        }
        
        return res;
    }
}

如果有大神能指正我的代码的错误。非常感谢!

猜你喜欢

转载自blog.csdn.net/qq_40147449/article/details/84074211
今日推荐