'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大小的矩阵,导致了内存超出了限制。。
因为已经纠结这题很久了,就没有再去想解决的方法。

这是我的代码

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-------------

你可能感兴趣的:('lintcode 树上最长距离')