给定一棵多叉树,求出这棵树的直径,即树上最远两点的距离。
包含n个结点,n-1条边的连通图称为树。
示例1的树如下图所示。其中4到5之间的路径最长,是树的直径,距离为5+2+4=11
数据范围:,保证最终结果满足
要求:空间复杂度:,时间复杂度
6,[[0,1],[1,5],[1,2],[2,3],[2,4]],[3,4,2,1,5]
11
2,[[0,1],[1,2]],[1]
1
import java.util.*; /* * public class Interval { * int start; * int end; * } */ public class Solution { /** * 树的直径 * @param n int整型 树的节点个数 * @param Tree_edge Interval类一维数组 树的边 * @param Edge_value int整型一维数组 边的权值 * @return int整型 */ List<List<Integer>> graph = new ArrayList<>(); //用来存图结构 Map<Integer, Map<Integer,Integer>> table =new HashMap<>(); //用来存图权重 int maxEdges=0; int maxIndex=-1; public int solve (int n, Interval[] Tree_edge, int[] Edge_value) { // write code here for(int i=0; i<n; i++){ graph.add( new ArrayList<Integer>()); } //构建graph,和table用于查询各边的权重 for(int i=0; i<Tree_edge.length;i++){ Interval edge=Tree_edge[i]; graph.get(edge.start).add(edge.end); //建立图 graph.get(edge.end).add(edge.start); //因为是无向图,所以也得反向连接一下 //构建表 if(!table.containsKey(edge.start)) table.put(edge.start, new HashMap<Integer, Integer>()); table.get(edge.start).put(edge.end,Edge_value[i]); if(!table.containsKey(edge.end)) table.put(edge.end, new HashMap<Integer, Integer>()); table.get(edge.end).put(edge.start,Edge_value[i]); } dfs(0,0,-1); dfs(0,maxIndex,-1); return maxEdges; } public void dfs(int count, int node, int parent){ List<Integer> cur = graph.get(node); for(int i=0; i<cur.size(); i++){ //可行性剪枝?反正就是不允许dfs往回走到父节点 if(cur.get(i)==parent){ continue; } int value=table.get(node).get(cur.get(i)); dfs(count+value, cur.get(i),node); } if(count>maxEdges){ maxEdges=count; maxIndex=node; } } }最后,这题叫简单吗?可QNMLGB吧。这题是二叉树问题吗(虽然之前也用二叉树写了一下,确实可以写)。。。这题明明就是无向图。。。
从任一点出发,找到该点到达最远的点p 从点p出发找到p点到达最远的点 q p q之间的距离即为树中最远的两个点 int point_p; int point_q; bool visit[100000]; int Max=-1; int max_len=-1; bool first_dfs=true;//第几次调用dfs int solve(int n, vector<Interval>& Tree_edge, vector<int>& Edge_value) { // write code here for(int i=0;i<n;i++) visit[i]=false; //初始化 dfs(Tree_edge[0].start,0,Tree_edge,Edge_value);//从任意一个点开始 找到该点所能到达的最远的点point_p for(int i=0;i<n;i++) visit[i]=false; //初始化 Max=-1; first_dfs=false; dfs(point_p,0,Tree_edge,Edge_value);//从point_p 找到该点所能到达的最远的点 point_q //那么point_p 到 point_q之间的距离即为 树的直径 for(int i=0;i<n;i++) visit[i]=false; //初始化 len(point_p,point_q,0,Tree_edge,Edge_value);//获得长度 return max_len; } bool len(int point1,int point2,int length,vector<Interval>& Tree_edge, vector<int>& Edge_value) { visit[point1]=true; if(point2==point1) //已经访问到该点 { max_len=length; return true; } for(int i=0;i<Tree_edge.size();i++) { //dfs 进入未访问的节点 if(Tree_edge[i].start==point1 && visit[Tree_edge[i].end]==false) { if(len(Tree_edge[i].end,point2,length+Edge_value[i],Tree_edge,Edge_value)) return true; } if(Tree_edge[i].end==point1 && visit[Tree_edge[i].start]==false) { if(len(Tree_edge[i].start,point2,length+Edge_value[i],Tree_edge,Edge_value)) return true; } } visit[point1]=false; return false; } void dfs(int point,int length, vector<Interval>& Tree_edge, vector<int>& Edge_value) { if(length>Max) //每访问一个点 { Max=length; if(first_dfs) point_p=point; else point_q=point; } visit[point]=true;//标记为已经访问 for(int i=0;i<Tree_edge.size();i++) { //dfs 进入未访问的节点 if(Tree_edge[i].start==point && visit[Tree_edge[i].end]==false) dfs(Tree_edge[i].end,length+Edge_value[i],Tree_edge,Edge_value); if(Tree_edge[i].end==point && visit[Tree_edge[i].start]==false) dfs(Tree_edge[i].start,length+Edge_value[i],Tree_edge,Edge_value); } visit[point]=false; }
本题需要1个注意的地方:
function solve( n , Tree_edge , Edge_value ) { let res = 0; const obj= {}; for (let i=0; i<Tree_edge.length; ++i) { const v = Tree_edge[i]; const w = Edge_value[i] || 0; obj[v.start] ? obj[v.start].push([w, v.end]): obj[v.start] = [[w, v.end]]; obj[v.end] ? obj[v.end].push([w, v.start]): obj[v.end] = [[w, v.start]]; } const dfs = (node, pre, w) => { let i=0; const arr = []; while(i<obj[node].length) { if (obj[node][i][1] !== pre) arr.push(dfs(obj[node][i][1], node, obj[node][i][0])); ++i; } arr.push(0, 0); // 防止没有 const one = Math.max(...arr); arr[arr.indexOf(one)] = -Infinity; const two = Math.max(...arr); if (one + two > res) res = one + two; return one + w; }; dfs(Tree_edge[0].start, -1, Edge_value[0]); return res; }
/** * struct Interval { * int start; * int end; * }; */ class Solution { public: /** * 树的直径 * @param n int整型 树的节点个数 * @param Tree_edge Interval类vector 树的边 * @param Edge_value int整型vector 边的权值 * @return int整型 */ int solve(int n, vector<Interval>& Tree_edge, vector<int>& Edge_value) { // build the tree vector<vector<pair<int, long>>> tree(n); for (int i = 0; i < Tree_edge.size(); ++i) { // key: 无向图要建双向边 const auto e = Tree_edge[i]; tree[e.start].emplace_back(e.end, Edge_value[i]); tree[e.end].emplace_back(e.start, Edge_value[i]); } int ans = 0; function<int(int, int, int)> dfs = [&](int cur, int parent, int weight) { int first = 0, second = 0; for (const auto& nei : tree[cur]) { if (nei.first == parent) continue; int len = dfs(nei.first, cur, nei.second); if (len > first) second = first, first = len; // 超过第一长的边,原先第一长的边就变第二长 else if (len > second) second = len; // 超过第二长的边,原先第一长的边还是第一长 } ans = max(ans, first + second); return weight + first; }; dfs(0, -1, 0); return ans; } };
function solve( n , Tree_edge , Edge_value ) { const tree = buildTree(n, Tree_edge, Edge_value); const visited = new Array(n).fill(false); const {max} = dfs({tree, visited}); return max; } function buildTree(n, tree_edge, edge_value) { const tree = new Array(n).fill(null).map(_ => []); for (let i = 0; i < tree_edge.length; i++) { const {start, end} = tree_edge[i]; const edge_val = edge_value[i]; tree[start].push({child: end, len: edge_val}); tree[end].push({child: start, len: edge_val}); } return tree; } function dfs({tree, visited, idx = 0, max = 0}) { if (tree[idx].length === 0 || visited[idx]) return 0; visited[idx] = true; let m1 = 0, m2 = 0; for (let i = 0; i < tree[idx].length; i++) { const {child, len} = tree[idx][i]; if (visited[child]) continue; const res = dfs({tree, visited, idx: child, max: max}); const distance = res.maxDistance + len; max = res.max; if (distance >= m1) { m2 = m1; m1 = distance; } else if (distance > m2) { m2 = distance; } } max = Math.max(max, m1 + m2); return {maxDistance: m1, max: max}; }
public class Solution { /** * 树的直径 * @param n int整型 树的节点个数 * @param Tree_edge Interval类一维数组 树的边 * @param Edge_value int整型一维数组 边的权值 * @return int整型 */ public int solve (int n, Interval[] Tree_edge, int[] Edge_value) { // write code here if(Tree_edge == null || Edge_value == null || Tree_edge.length != Edge_value.length){return 0;} Map<Integer, List<Edge>> graph = new HashMap<>(); int len = Tree_edge.length; for(int i = 0; i < len; ++i){ Interval inter = Tree_edge[i]; int start = inter.start; int end = inter.end; int w = Edge_value[i]; Edge e1 = new Edge(end, w); if(!graph.containsKey(start)){ List<Edge> temp = new ArrayList<>(); graph.put(start, temp); } graph.get(start).add(e1); Edge e2 = new Edge(start, w); if(!graph.containsKey(end)){ List<Edge> temp = new ArrayList<>(); graph.put(end, temp); } graph.get(end).add(e2); } int[] remote = {0, 0}; // remote[0] 代表以0为起点的最长路径长度, remote[1]代表最长路径的终点 dfs(graph, 0, -1, 0, remote); int[] res = {0, 0}; dfs(graph, remote[1], -1, 0, res); return res[0]; } private class Edge{ int end; int w; Edge(int end, int w){ this.end = end; this.w = w; } } private void dfs(Map<Integer, List<Edge>> graph, int from, int prev, int path, int[] res){ List<Edge> edges = graph.get(from); for(Edge edge: edges){ if(edge.end != prev){ path += edge.w; if(path > res[0]){ res[0] = path; res[1] = edge.end; } dfs(graph, edge.end, from, path, res); path -= edge.w; // 回溯 } } } }
int postOrder(unordered_map<int, vector<pair<int,int>>> &tree, int node, int &res,int parent){ vector<int> children; for(auto child : tree[node]){ if(child.first != parent){ int len = postOrder(tree,child.first,res,node); children.push_back(child.second + len); } } if(children.size() == 0){ return 0; } sort(children.begin(),children.end(),greater<int>()); int len = children[0]; int maxLen = len; if(children.size() > 1){ maxLen += children[1]; } res = max(maxLen,res); return len; } int solve(int n, vector<Interval>& Tree_edge, vector<int>& Edge_value) { if(Tree_edge.size() == 0){ return 0; } unordered_map<int, vector<pair<int,int>>> tree; for(int i=0;i<Tree_edge.size();i++){ Interval edge = Tree_edge[i]; int value = Edge_value[i]; if(tree.find(edge.start) == tree.end()){ tree[edge.start] = vector<pair<int,int>>(); } if(tree.find(edge.end) == tree.end()){ tree[edge.end] = vector<pair<int,int>>(); } tree[edge.start].push_back(make_pair(edge.end,value)); tree[edge.end].push_back(make_pair(edge.start,value)); } int res = 0; int root = Tree_edge[0].start; postOrder(tree,root,res,root); return res; }
参考leetcode上的1245. Tree Diameter
可以把树看作是一个没有环的无向图,使用深度优先搜素的思想遍历整棵树。由于没有环,所有不需要visit数组记录访问过的节点,只需要每次传入父节点保证子节点不会返回访问父节点。
class Edge { int neighbor; int weight; Edge(int neighbor, int weight) { this.neighbor = neighbor; this.weight = weight; } } public class Solution { private int diameter = 0; public int solve (int n, Interval[] Tree_edge, int[] Edge_value) { // 使用数组保存所有的节点 List<Edge>[] graph = new List[n]; for (int i = 0; i < n; i++) { graph[i] = new ArrayList<>(); } for (int i = 0; i < Tree_edge.length; i++) { Interval interval = Tree_edge[i]; int value = Edge_value[i]; // 由于是无向图,所有每条边都是双向的 graph[interval.start].add(new Edge(interval.end, value)); graph[interval.end].add(new Edge(interval.start, value)); } // 随机从一个节点开始dfs,这里选择的是0 dfs(graph, 0, -1); return diameter; } // dfs返回值为从node节点开始的最长深度 private int dfs(List[] graph, int node, int parent) { int maxDepth = 0; //从节点开始的最长深度 int secondMaxDepth = 0; //从节点开始的第二长深度 for (Edge edge : graph[node]) { int neighbor = edge.neighbor; if (neighbor == parent) continue; // 防止返回访问父节点 int depth = edge.weight + dfs(graph, neighbor, node); if (depth > maxDepth) { secondMaxDepth = maxDepth; maxDepth = depth; }else if (depth > secondMaxDepth) { secondMaxDepth = depth; } } // maxDepth + secondMaxDepth为以此节点为中心的直径 diameter = Math.max(diameter, maxDepth + secondMaxDepth); return maxDepth; } }
# class Interval: # def __init__(self, a=0, b=0): # self.start = a # self.end = b # # 树的直径 # @param n int整型 树的节点个数 # @param Tree_edge Interval类一维数组 树的边 # @param Edge_value int整型一维数组 边的权值 # @return int整型 # from collections import defaultdict class Solution: def solve(self , n , Tree_edge , Edge_value ): # write code here graph, table = {}, defaultdict() for i in range(len(Tree_edge)): graph.setdefault(Tree_edge[i].start, []).append(Tree_edge[i].end), graph.setdefault(Tree_edge[i].end, []).append(Tree_edge[i].start) table[(Tree_edge[i].start, Tree_edge[i].end)], table[(Tree_edge[i].end, Tree_edge[i].start)] = Edge_value[i], Edge_value[i] self.res, self.maxIndex = 0, -1 def dfs(cnt, node, parent): cur = graph[node] for i in range(len(cur)): if cur[i] == parent: continue dfs(cnt+table[(node,cur[i])], cur[i], node) if cnt > self.res: self.res = cnt self.maxIndex = node dfs(0, 0, -1) dfs(0, self.maxIndex, -1) return self.res
#include <vector> #include <unordered_map> #include <list> #include <algorithm> using namespace std; class Solution { public: /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * 树的直径 * @param n int整型 树的节点个数 * @param Tree_edge Interval类vector 树的边 * @param Edge_value int整型vector 边的权值 * @return int整型 */ int solve(int n, vector<Interval>& Tree_edge, vector<int>& Edge_value) { // 如果边或权值数组为空,或者长度不匹配,返回0 if (Tree_edge.empty() || Edge_value.empty() || Tree_edge.size() != Edge_value.size()) return 0; // 构建图的邻接表 unordered_map<int, list<Edge>> graph; int len = Tree_edge.size(); for (int i = 0; i < len; ++i) { int start = Tree_edge[i].start; int end = Tree_edge[i].end; int w = Edge_value[i]; // 添加边 start -> end graph[start].emplace_back(end, w); // 添加边 end -> start (无向图) graph[end].emplace_back(start, w); } // 记录以节点0为起点的最长路径长度和终点 pair<int, int> remote = {0, 0}; dfs(graph, 0, -1, 0, remote); // 以远端节点为新的起点再次进行DFS,计算最长路径 pair<int, int> result = {0, 0}; dfs(graph, remote.second, -1, 0, result); return result.first; // 返回最长路径长度 } private: // 边的结构体,包含终点和权重 struct Edge { int end; int weight; Edge(int e, int w) : end(e), weight(w) {} }; // 深度优先搜索,用于找到最长路径 void dfs(unordered_map<int, list<Edge>>& graph, int from, int prev, int path, pair<int, int>& res) { // 遍历当前节点的所有相邻边 for (const auto& edge : graph[from]) { if (edge.end != prev) { // 跳过回到父节点的边 path += edge.weight; // 更新最长路径信息 if (path > res.first) { res.first = path; res.second = edge.end; } // 继续递归DFS dfs(graph, edge.end, from, path, res); path -= edge.weight; // 回溯,恢复路径长度 } } } };
class Solution: def solve(self , n: int, Tree_edge: List[Interval], Edge_value: List[int]) -> int: g = [[] for _ in range(n)] for i, w in zip(Tree_edge, Edge_value): g[i.start].append([i.end, w]) g[i.end].append([i.start, w]) res = 0 def dfs(root: int, fa: int) -> int: p = 0 for e, w in g[root]: if e == fa: continue c = dfs(e, root) + w nonlocal res res = max(res, c + p) p = max(p, c) return p dfs(0, -1) return res
import java.util.*; public class Solution { public int solve(int n, Interval[] Tree_edge, int[] Edge_value) { // 创建邻接表,记录节点及对应边的权重 Map<Integer, List<int[]>> graph = new HashMap<>(); for (int i = 0; i < Tree_edge.length; i++) { Interval edge = Tree_edge[i]; int start = edge.start; int end = edge.end; int weight = Edge_value[i]; graph.computeIfAbsent(start, k -> new ArrayList<>()).add(new int[]{end, weight}); graph.computeIfAbsent(end, k -> new ArrayList<>()).add(new int[]{start, weight}); } // 第一次 BFS,找到任意起点到最远点 A int[] farthest = bfs(graph, 0); // 第二次 BFS,从 A 出发找到最远距离 int[] result = bfs(graph, farthest[0]); return result[1]; // result[1] 存储的是最大距离 } // 辅助方法,进行 BFS 并返回最远点及其距离 private int[] bfs(Map<Integer, List<int[]>> graph, int start) { Queue<int[]> queue = new LinkedList<>(); Map<Integer, Boolean> visited = new HashMap<>(); queue.offer(new int[]{start, 0}); // 数组内部:[当前节点, 当前距离] visited.put(start, true); int farthestNode = start; int maxDistance = 0; while (!queue.isEmpty()) { int[] current = queue.poll(); int currentNode = current[0]; int currentDistance = current[1]; if (currentDistance > maxDistance) { maxDistance = currentDistance; farthestNode = currentNode; } // 遍历当前节点的所有邻接节点 if (graph.containsKey(currentNode)) { for (int[] neighbor : graph.get(currentNode)) { if (!visited.getOrDefault(neighbor[0], false)) { visited.put(neighbor[0], true); queue.offer(new int[]{neighbor[0], currentDistance + neighbor[1]}); } } } } return new int[]{farthestNode, maxDistance}; } } // 辅助类,用于表示边的起点和终点 class Interval { int start; int end; public Interval(int start, int end) { this.start = start; this.end = end; } }
import java.util.*; /* * public class Interval { * int start; * int end; * public Interval(int start, int end) { * this.start = start; * this.end = end; * } * } */ public class Solution { class Edge { int to; int weight; public Edge(int to, int weight) { this.to = to; this.weight = weight; } } /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * 树的直径 * @param n int整型 树的节点个数 * @param Tree_edge Interval类一维数组 树的边 * @param Edge_value int整型一维数组 边的权值 * @return int整型 */ int max = Integer.MIN_VALUE; boolean visited[][]; public int solve (int n, Interval[] Tree_edge, int[] Edge_value) { // write code here // 转临接表 HashMap<Integer, ArrayList<Edge>> map = new HashMap<>(); visited = new boolean[n][n]; for(int i = 0; i < Tree_edge.length; i++) { Interval edge = Tree_edge[i]; map.putIfAbsent(edge.start, new ArrayList<>()); map.putIfAbsent(edge.end, new ArrayList<>()); map.get(edge.start).add(new Edge(edge.end, Edge_value[i])); map.get(edge.end).add(new Edge(edge.start, Edge_value[i])); } dfs(0, map); return max; } public int dfs(int curIndex, HashMap<Integer, ArrayList<Edge>> map) { int s1 = 0; int s2 = 0; List<Edge> sonList = map.get(curIndex); for(int i = 0; i <sonList.size(); i++) { int to = sonList.get(i).to; int weight = sonList.get(i).weight; if(visited[curIndex][to]) continue; visited[curIndex][to] = true; visited[to][curIndex] = true; int son = dfs(to, map) + weight; if(son > s1) { s2 = s1; s1 = son; } else if(s2 < son && s1 > son) s2 = son; } max = Math.max(max, Math.max(s1, s1 + s2)); return s1; } }
/** * struct Interval { * int start; * int end; * }; */ class Solution { public: /** * 树的直径 * @param n int整型 树的节点个数 * @param Tree_edge Interval类vector 树的边 * @param Edge_value int整型vector 边的权值 * @return int整型 */ vector<vector<pair<int, pair<int, bool>>>> graph;//注:这里的空间复杂度实际是O(2n) int solve(int n, vector<Interval>& Tree_edge, vector<int>& Edge_value) { graph.resize(n); for (int i = 0; i < n - 1; i++) { graph[Tree_edge[i].start].push_back(pair<int, pair<int, bool>>(Tree_edge[i].end, pair<int, bool>(Edge_value[i], false))); graph[Tree_edge[i].end].push_back(pair<int, pair<int, bool>>(Tree_edge[i].start, pair<int, bool>(Edge_value[i], false))); } return bfs(bfs(0, 0).first, 0).second; } pair<int, int> bfs(int i, int len) {/*i是接下来走哪里, len是已经走了多远*/ pair<int, int> farmost(i, len); //<最远走到了哪里, 最远走了多远> for (auto& it : graph[i]) { if (it.second.second) continue; it.second.second = true; auto jt = graph[it.first].begin(); for (; jt != graph[it.first].end(); jt++) if (jt->first == i) { jt->second.second = true; break; } pair<int, int> temp = bfs(it.first, len + it.second.first); if (temp.second > farmost.second)farmost = temp; it.second.second = false; jt->second.second = false; } return farmost; } };