【力扣每日一题】力扣2846边权重均等查询

本文讨论了解决力扣2846题中的边权重均等查询问题,首先尝试用DFS在图中寻找路径,然后转向考虑树结构,利用公共祖先节点的方法。最后提到可能通过旋转构建平衡树或使用未提及的Tarjan算法来提高效率。
摘要由CSDN通过智能技术生成

题目来源

力扣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算法,这个算法没有听说过,目前还没有时间,后面有空再进行学习吧。

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值