树直径问题其实就好像在一个无向无环图中找一条最长的路径,核心思想其实也很简单:
首先从任意一个节点开始BFS找距离最远能到达的点(以该点作为根节点树的最深层),假设到达点为V,再以V为根节点找最远能到达的点(即以V为根节点树的最深层),两次BFS即可解决。
按照上述方法,其实最开始任意选的那个点就是最长路径中的一个节点而已,这个节点可能是最长路径的端点也有可能是路径中的一点。
代码:
#include <bits/stdc++.h>
using namespace std;
class Graph {
int V;
list<int> *adj;
public:
Graph(int v) : V(v){adj = new list<int>[V];}
void addEdge(int u, int v);
void longestPathLength();
pair<int, int >BFS(int u);
};
void Graph::addEdge(int u, int v) {
adj[u].push_back(v);
adj[v].push_back(u);
}
pair<int, int> Graph::BFS(int u) {
int dis[V];
fill(dis, dis + V, -1);
queue<int> q;
q.push(u);
dis[u] = 0;
while(!q.empty()) {
int t = q.front();
q.pop();
for(auto it = adj[t].begin(); it != adj[t].end(); ++it) {
if(dis[*it] == -1) {
q.push(*it);
dis[*it] = dis[t] + 1;
}
}
}
int maxDis = 0;
int idx = -1;
for(int i = 0; i < V; ++i) {
if(dis[i] > maxDis) {
idx = i;
maxDis = dis[i];
}
}
return make_pair(idx, maxDis);
}
void Graph::longestPathLength() {
pair<int, int> t1, t2;
t1 = BFS(0);
t2 = BFS(t1.first);
cout << "Longest path is from " << t1.first << " to " << t2.first << " of length " << t2.second << endl;
}
int main(){
ios::sync_with_stdio(false);
Graph g(10);
g.addEdge(0, 1);
g.addEdge(1, 2);
g.addEdge(2, 3);
g.addEdge(2, 9);
g.addEdge(2, 4);
g.addEdge(4, 5);
g.addEdge(1, 6);
g.addEdge(6, 7);
g.addEdge(6, 8);
g.longestPathLength();
return 0;
}
对于求二叉树的直径其实更简单,取根节点的左右孩子树高之和加一和左右孩子中的直径三者中的最大值(直径可能不包含根节点),同理孩子节点递归向下求,核心代码:
int Diameter(Node *root, int *hegiht) {
if(root == NULL) {
*hegiht = 0;
return 0;
}
int lh = 0, rh = 0;
int ldiameter = 0, rdiameter = 0;
ldiameter = Diameter(root->left, &lh);
rdiameter = Diameter(root->right, &rh);
*height = max(lh, rh) + 1; // recording height of tree
return max(lh + rh + 1, max(ldiameter, rdiameter));
}