我有一个无向图,它代表了Facebook等社交媒体中的用户连接. 有N个 node ,从1开始到N 边由开始数组和结束数组表示. 任务数组表示我有兴趣查找该 node 的连接的 node 编号(即社交媒体中的用户).

Example:

N = 5
From = [2,2,1,1]
To = [1,3,3,4]
Task = [4,2,5]

Answer:

[4,4,1]

Explanation:

图表如下所示:

enter image description here

Now for Task [4,2,5]

4 -> [1,2,3,4] The node 4 has these connections 
2 -> [1,2,3,4] The node 2 has these connections 
5 -> [5]

因此结果是[4,4,1]

Constraints:

N=2 to 10^5
size of arrays from, 'to', and tasks is 2 to 10^5

这是一个HackerRank问题.我的代码在15个测试用例中有8个失败,显示大型输入出现超时错误.

以下是我的代码:

public static List<Integer> solve(int N, List<Integer> from, List<Integer> to, List<Integer> tasks) {
    int n = from.size();
    // Create the graph
    Map<Integer, Set<Integer>> map = new HashMap<>();
    for(int i=0; i<n; i++) {
        int key1 = from.get(i);
        int key2 = to.get(i);
        
        Set<Integer> value = map.getOrDefault(key1, new HashSet<>());
        value.add(key2);
        map.put(key1, value);
        
        value = map.getOrDefault(key2, new HashSet<>());
        value.add(key1);
        map.put(key2, value);       
    }
    List<Integer> result = new ArrayList<>();
    for(int node: tasks) {
        result.add(bfs(map, node));
    }
    return result;
}
    // Solve using breadth first search approach
public static int bfs(Map<Integer, Set<Integer>> map, int node) {
    Set<Integer> visited = new HashSet<>();
    Queue<Integer> q = new LinkedList<>();
    int count = 0;
    visited.add(node);
    q.add(node);
    while(!q.isEmpty()) {
        node = q.poll();
        count++;
        Set<Integer> val = map.get(node);
        if(val != null) {
            for(int next : val) {
                if(visited.add(next)) {
                    q.add(next);
                }
            }
        }
    }
    return count;
}

我也try 了递归方法,仍然是同样的问题,对于大输入大小值,我得到了超时错误.

如何降低此代码的时间复杂度.

推荐答案

当输入较大时,BFS算法将一遍又一遍地运行相同的图组件,始终派生相同的 node 计数.这真是太可惜了.一种解决方案是立即重复第二次BFS,然后使用您在第一阶段中找到的计数来标记访问的 node .每当要在已经具有该标记的 node 上调用BFS时,只需返回该标记并跳过BFS执行即可.

备选方案:不相交集

你可以创造disjoint-set data structure分,而不是graph分.该 struct 知道 node 所属的component,并且可以在填充 struct 时跟踪组件的大小.它并不精确地跟踪图的所有边,而是每个 node 只维护一个链接,只是为了跟踪组件成员资格.

有几种可选的算法可以合并两个组件.一种是"按大小联盟",这在这里似乎是合适的,因为我们对大小感兴趣.

下面是一个DisjointSets类的可能实现:

import java.util.*;

class DisjointSets<T> {
    private class Node {
        Node parent;
        int size;
        T key;

        Node(T key) {
            this.key = key;
            this.size = 1;  // The node starts as its own component
            this.parent = this;
        }
    }

    Map<T, Node> nodes = new HashMap<>();

    private Node find(T key) {
        Node node = nodes.computeIfAbsent(key, Node::new);
        while (node.parent != node) {
            node = node.parent = node.parent.parent; // Path halving
        }
        return node;
    }

    public void union(T keyA, T keyB) {
        Node nodeA = find(keyA);
        Node nodeB = find(keyB);
        if (nodeA == nodeB) return; // Already in same set
        if (nodeA.size < nodeB.size) {
            nodeA.parent = nodeB;
            nodeB.size += nodeA.size;
        } else {
            nodeB.parent = nodeA;
            nodeA.size += nodeB.size;
        }
    }

    public int size(T key) {
        return find(key).size;
    }
}

然后,solve函数可以是:

    public static List<Integer> solve(int N, List<Integer> from, List<Integer> to, List<Integer> tasks) {
        int n = from.size();
        DisjointSets<Integer> set = new DisjointSets<>();
        for (int i = 0; i < n; i++) {
            set.union(from.get(i), to.get(i)); // populate disjoint sets
        }
        List<Integer> result = new ArrayList<>();
        for (int node : tasks) {
            result.add(set.size(node));
        }
        return result;
    }

Java相关问答推荐

Selenium Java:无法访问IFRAME内部的元素

将偶数元素移动到数组的前面,同时保持相对顺序

同时运行JUnit测试和Selenium/Cucumber测试时出现问题

将数组整体转换为链接表

通过合并Akka Streams中的多个慢源保持订购

Spring Boot@Cachebale批注未按预期工作

为什么一个Test的instance?& gt;在构造函数中接受非空对象?

R.id.main给我一个红色错误,无法解析MainActivity.java中的符号main

使用Spring Boot3.2和虚拟线程的并行服务调用

在Java中如何从Executors.newFixedThreadPool(MAX_THREAD_COUNT())迁移到虚拟线程

如何从Keyloak映射Hibernate实体中的用户

如何在Microronaut中将 map 读取为 map

为什么当我创建Robot对象时,JavaFX引发IlLegalStateException异常?

如何在我的世界中为互动增加冷却时间?

如何在EL处理器中定义带有命名空间的变量?

Spring Validator批注不起作用

如何在Maven Central上部署?

如何制作回文程序?

我无法在我的Spring Boot应用程序中导入CSV依赖项

获取月份';s在java中非UTC时区的开始时间和结束时间