Я делаю this problem на Hackerrank. Краткое описание проблемы:Быстрая топологическая сортировка, когда порядок узлов значителен?
Вы пытаетесь восстановить последовательность из M различных целых чисел в диапазоне [1, 10^6]. Вам дано 1 < = N < = 10^3 подпоследовательности длины 2 < = K < = 10^3. Если возможны две последовательности, верните лексикографически меньшую.
Мой алгоритм выглядит следующим образом:
Создайте вершину для каждого отдельного целого. Храните их в хэш-карте.
Для каждой строки, если
i
предшествуетj
в строке, добавить ребро изi
кj
. Отслеживайте степень каждой вершины.Сделать приоритетную очередь, ключ которой является значением каждой вершины. Завершите все вершины с неопределенностью 0.
Пока очередь непустая: поместите верхнюю вершину. Сократите зависимость каждого из своих детей.
Мои ответы верны, но я превысил лимит времени на больших тестовых шкафах. Я думаю, что приоритетная очередь является узким местом, но я не могу придумать способ сохранить вершины, отсортированные по значению менее чем O(log n)
. Мой код выглядит следующим образом, с классом Vertex исключены держать ее короче --- это в основном только добытчиками и сеттеров:
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;
}
}
Что я делаю слишком медленно? Я предоставил свой код ради того, чтобы сделать его конкретным, но я действительно ищу алгоритмический ответ.
Как вы можете определить, является ли один элемент непосредственным преемником другого, не делая топологический вид? Не гарантируется, что элементы в подпоследовательностях смежны друг с другом в исходной последовательности. –
А, я вижу. Ребро от вершины до его первого ребенка достаточно, чтобы обеспечить упорядочение, так как упорядочение «X появляется перед Y» транзитивно. Благодаря! –