力扣2846边权重均等查询
刚开始看到这道题,注意到了是一个在树中找路径的问题,于是选择了把树当作图,来寻找两点之间的路径。(这里使用了DFS来找路径)
class Solution {
private List[] adjacencyList;
private int n;
public int[] minOperationsQueries(int n, int[][] edges, int[][] queries) {
this.n = n;
// 建立并初始化邻接表
this.adjacencyList = (List[]) 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 distancesMapCount = new HashMap<>();
while (index < path.length && path[index] != -1) {
List 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 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 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 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 getChildren() {
return children;
}
}
还是超出了时间限制 编辑
或许在构建树的时候进行旋转,最终把树构建成平衡树结果会好一点。 最后看了官方答案,要使用到Tarjan算法,这个算法没有听说过,目前还没有时间,后面有空再进行学习吧。