当节点的顺序很重要时,快速拓扑排序?

时间:2015-02-05 19:42:32

标签: java algorithm graph topological-sort

我在Hackerrank上正在做this problem。问题摘要是:

  

您正在尝试重建[1,10 ^ 6]范围内的M个不同整数的序列。给予1&lt; = N <= 10 ^ 3个长度为2 <= K <= 10 ^ 3的子序列。如果可能有两个序列,则返回字典缩小的序列。

我的算法如下:

  1. 为每个不同的整数创建一个顶点。将它们存储在哈希映射中。

  2. 对于每一行,如果i位于行前j之前,请添加ij的边。跟踪每个顶点的不确定性。

  3. 创建一个优先级队列,其关键是每个顶点的值。将所有顶点排列为indegree 0.

  4. 队列非空时:弹出顶部顶点。减少每个孩子的不确定性。

  5. 我的回答是正确的,但我在较大的测试用例上超出了时间限制。我认为优先级队列是瓶颈,但我想不出一种方法来保持顶点按值排序小于O(log n)。我的代码如下,将Vertex类排除在外以使其更短 - 它主要只是getter和setter:

    class FavoriteSequence {
        private Map<Integer, Vertex> seen;
    
        public void solve(int testNumber, Scanner in, PrintWriter out) {
            int numRows = in.nextInt();
            seen = new HashMap<>();
    
            for (int i = 0; i < numRows; i++) {
                int numInRow = in.nextInt();
                List<Vertex> row = IntStream.range(0, numInRow).mapToObj(x -> getVert(in.nextInt())).collect(
                        Collectors.toList());
    
                int idx = 0;
                for (Vertex v : row) {
                    v.incInDegree(idx);
                    v.addChildren(row.subList(++idx, numInRow));
                }
            }
    
            List<String> ans = new LinkedList<>();
            Queue<Vertex> bfsQ = new PriorityQueue<>(new Comparator<Vertex>() {
                public int compare(Vertex o1, Vertex o2) {
                    int valCmp = Integer.compare(o1.getValue(), o2.getValue());
                    return valCmp;
                }
            });
    
            bfsQ.addAll(seen.values().stream().filter(c -> c.getInDegree() == 0).collect(Collectors.toList()));
    
            while (!bfsQ.isEmpty()) {
                Vertex me = bfsQ.poll();
                ans.add(Integer.toString(me.getValue()));
    
                for (List<Vertex> cs : me.getChildrens()) {
                    for (Vertex c : cs) {
                        if (c.decInDegree() == 0) {
                            bfsQ.add(c);
                        }
                    }
                }
            }
    
            out.println(String.join(" ", ans));
        }
    
        private Vertex getVert(int idx) {
            Vertex me = seen.get(idx);
    
            if (me == null) {
                me = new Vertex(idx);
                seen.put(idx, me);
            }
    
            return me;
        }
    }
    

    我做得太慢了?为了使其具体化,我提供了我的代码,但我真的在寻找算法的答案。

1 个答案:

答案 0 :(得分:2)

如果我没弄错,这段代码

        int idx = 0;
        for (Vertex v : row) {
            v.incInDegree(idx);
            v.addChildren(row.subList(++idx, numInRow));
        }

添加弧,其数量与子序列的长度成二次方增长。实际上,只需要在传递减少中添加弧,即从子序列的每个元素添加到其直接后继者。