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大小的矩阵,导致了内存超出了限制。。
因为已经纠结这题很久了,就没有再去想解决的方法。
这是我的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
|
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> cost,const int tar, int & _max, int & END) { int n = cost.size(),top = -1, j, s[10007]; vector 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 &starts, vector &ends, vector &lens) { // Write your code here vector> 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
|
/** * 本参考程序来自九章算法,由 @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 neighbors;
public TreeNode(int val) { this.val = val; neighbors = new HashMap<>(); } }
class Pair implements Comparable { 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 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 pq = new PriorityQueue<>(); pq.offer(new Pair(node, 0));
while (!pq.isEmpty()) { Pair curt = pq.poll(); res = curt; for (Map.Entry 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; } }
|
如果有大神能指正我的代码的错误。非常感谢!
-------------end of file
thanks for reading-------------