题目来源
力扣2846边权重均等查询
解题过程
思路一
刚开始看到这道题,注意到了是一个在树中找路径的问题,于是选择了把树当作图,来寻找两点之间的路径。(这里使用了DFS来找路径)
代码实现一
class Solution {private List<Route>[] adjacencyList;private int n;public int[] minOperationsQueries(int n, int[][] edges, int[][] queries) {this.n = n;// 建立并初始化邻接表this.adjacencyList = (List<Route>[]) new List<?>[n];for (int i = 0; i < n; i++) {adjacencyList[i] = new ArrayList<>();}for (int[] edge : edges) {adjacencyList[edge[0]].add(new Route(edge[1], edge[2]));adjacencyList[edge[1]].add(new Route(edge[0], edge[2]));}int[] answer = new int[queries.length];for (int i = 0; i < queries.length; i++) {int[] query = queries[i];int[] path = findPath(query[0],query[1]);int index = 1;// 使用哈希表保存距离及该距离在路径中出现次数映射Map<Integer, Integer> distancesMapCount = new HashMap<>();while (index < path.length && path[index] != -1) {List<Route> routes = adjacencyList[path[index - 1]];for (Route route : routes) {if (route.getDestination() == path[index]){int key = route.getDistance();distancesMapCount.put(key, distancesMapCount.getOrDefault(key, 0) + 1);break;}}index++;}// 总路径数-最多的距离次数就是需要调整的次数int sum = 0;int max = 0;for (Integer value : distancesMapCount.values()) {sum += value;max = Math.max(max, value);}answer[i] = sum - max;}return answer;}// 获取两点之间的路径private int[] findPath(int departure, int destination) {// 访问数组boolean[] visit = new boolean[this.n];// 路径数组int[] path = new int[this.n];int current = path[0] = departure;visit[current] = true;int length = dfs(current,destination,visit,path,1);for (;length < this.n; length++) {path[length] = -1;}return path;}// 深搜获取路径private int dfs(int current, int destination,boolean[] visit, int[] path, int length) {if (current == destination) {return length;}List<Route> routes = this.adjacencyList[current];for (Route route: routes) {int next = route.getDestination();if (!visit[next]) {visit[next] = true;path[length] = next;int temp = dfs(next, destination, visit, path, length + 1);if (temp != -1) {return temp;}}}return -1;}
}/*** 路由类*/
class Route{// 终点private int destination;// 距离private int distance;public Route(int destination, int distance) {this.destination = destination;this.distance = distance;}public int getDestination() {return destination;}public int getDistance() {return distance;}
}
结果一
结果超出了时间限制 编辑
思路二
后来想到,树节点之间的路径其实可以看成两个节点向上寻找公共祖先节点的过程。
代码实现二
class Solution {public int[] minOperationsQueries(int n, int[][] edges, int[][] queries) {TreeNode[] treeNodes = createTree(edges,n);// 寻找根节点TreeNode root = treeNodes[0];while (root.getParent() != null) {root = root.getParent();}setDepth(root,1);int[] answers = new int[queries.length];for (int i = 0; i < queries.length; i++) {int[] query = queries[i];Map<Integer, Integer> distanceMapCount = new HashMap<>();TreeNode shallow = treeNodes[query[0]];TreeNode deep = treeNodes[query[1]];// 调整两个节点深度一样if (shallow.getDepth() > deep.getDepth()) {TreeNode temp = shallow;shallow = deep;deep = temp;}while (deep.getDepth() > shallow.getDepth()) {int distance = deep.getToParentDistance();distanceMapCount.put(distance, distanceMapCount.getOrDefault(distance, 0) + 1);deep = deep.getParent();}// 同时向上寻找共同祖先节点while (deep != shallow){int distance = deep.getToParentDistance();distanceMapCount.put(distance, distanceMapCount.getOrDefault(distance, 0) + 1);distance = shallow.getToParentDistance();distanceMapCount.put(distance, distanceMapCount.getOrDefault(distance, 0) + 1);deep = deep.getParent();shallow = shallow.getParent();}int sum = 0;int max = 0;for (Integer value : distanceMapCount.values()) {sum += value;max = Math.max(max,value);}answers[i] = sum - max;}return answers;}// 设置每个节点的深度private void setDepth(TreeNode parent, int depth) {if (parent.getChildren().size() == 0) {return;}for (TreeNode child : parent.getChildren()) {child.setDepth(depth);setDepth(child, depth + 1);}}// 建立树private TreeNode[] createTree(int[][] edges, int nodeCount) {TreeNode[] treeNodes = new TreeNode[nodeCount];for (int i = 0; i < nodeCount; i++) {treeNodes[i] = new TreeNode(i);}for (int i = 0; i < edges.length;i++) {int point1 = edges[i][0];int point2 = edges[i][1];if (treeNodes[point2].getParent() == null) {treeNodes[point2].setParent(treeNodes[point1]);treeNodes[point1].getChildren().add(treeNodes[point2]);treeNodes[point2].setToParentDistance(edges[i][2]);;}else {treeNodes[point1].setParent(treeNodes[point2]);treeNodes[point2].getChildren().add(treeNodes[point1]);treeNodes[point1].setToParentDistance(edges[i][2]);;}}return treeNodes;}}/***树类*/
class TreeNode{// 父节点private TreeNode parent;// 节点数据private int point;// 到父节点的边权重private int toParentDistance;// 孩子节点private List<TreeNode> children;// 深度private int depth;public TreeNode(int point) {this.parent = null;this.point = point;this.children = new ArrayList<>();this.depth = 0;}public int getToParentDistance() {return toParentDistance;}public void setToParentDistance(int toParentDistance) {this.toParentDistance = toParentDistance;}public int getDepth() {return depth;}public void setDepth(int depth) {this.depth = depth;}public void setParent(TreeNode parent) {this.parent = parent;}public TreeNode getParent() {return parent;}public int getPoint() {return point;}public List<TreeNode> getChildren() {return children;}
}
结果二
还是超出了时间限制 编辑
总结
或许在构建树的时候进行旋转,最终把树构建成平衡树结果会好一点。 最后看了官方答案,要使用到Tarjan算法,这个算法没有听说过,目前还没有时间,后面有空再进行学习吧。