685. Redundant Connection II

Der Aufgabentext wird für die gewählte Sprache aus dem Russischen übersetzt. Code bleibt unverändert.

В этой задаче корневое Baum — это направленный Graph, в котором существует ровно один узел (корень), для которого все остальные узлы являются потомками этого узла, плюс каждый узел имеет ровно одного родителя, за исключением корневого узла, у которого нет родителей.

Данный ввод представляет собой направленный Graph, который изначально был корневым Baumм с n узлами (со значениями от 1 до n), и к которому добавлено одно дополнительное направленное edge. Добавленное edge соединяет две разные вершины, выбранные из 1 до n, и это edge не существовало ранее.

Результирующий Graph представлен в виде двумерного Arrayа ребер. Каждый element Arrayа edges — это пара [ui, vi], представляющая направленное edge, соединяющее узлы ui и vi, где ui является родителем ребенка vi.

return edge, которое можно удалить, чтобы результирующий Graph стал корневым Baumм с n узлами. Если существует несколько ответов, return ответ, который встречается последним в данном двумерном Arrayе.

Beispiel:

Input: edges = [[1,2],[1,3],[2,3]]

Output: [2,3]

C# Lösung

zugeordnet/original
public class Solution {
    public int[] FindRedundantDirectedConnection(int[][] edges) {
        int N = edges.Length;
        var parent = new Dictionary<int, int>();
        var candidates = new List<int[]>();
        foreach (var edge in edges) {
            if (parent.ContainsKey(edge[1])) {
                candidates.Add(new int[] { parent[edge[1]], edge[1] });
                candidates.Add(edge);
            } else {
                parent[edge[1]] = edge[0];
            }
        }
        int root = Orbit(1, parent).Node;
        if (candidates.Count == 0) {
            var cycle = Orbit(root, parent).Seen;
            foreach (var edge in edges) {
                if (cycle.Contains(edge[0]) && cycle.Contains(edge[1])) {
                    return edge;
                }
            }
        }
        var children = parent.GroupBy(kvp => kvp.Value).ToDictionary(g => g.Key, g => g.Select(kvp => kvp.Key).ToList());
        var seen = new bool[N + 1];
        var stack = new Stack<int>();
        stack.Push(root);
        while (stack.Count > 0) {
            int node = stack.Pop();
            if (!seen[node]) {
                seen[node] = true;
                if (children.ContainsKey(node)) {
                    foreach (int c in children[node]) stack.Push(c);
                }
            }
        }
        return seen.Any(b => !b) ? candidates[0] : candidates[1];
    }
    public class OrbitResult {
        public int Node { get; }
        public HashSet<int> Seen { get; }
        public OrbitResult(int node, HashSet<int> seen) {
            Node = node;
            Seen = seen;
        }
    }
    public OrbitResult Orbit(int node, Dictionary<int, int> parent) {
        var seen = new HashSet<int>();
        while (parent.ContainsKey(node) && !seen.Contains(node)) {
            seen.Add(node);
            node = parent[node];
        }
        return new OrbitResult(node, seen);
    }
}

C++ Lösung

Auto-Entwurf, vor dem Einreichen prüfen
#include <bits/stdc++.h>
using namespace std;

// Auto-generated C++ draft from the C# solution. Review containers, LINQ and helper types before submit.
class Solution {
public:
    public vector<int>& FindRedundantDirectedConnection(int[][] edges) {
        int N = edges.size();
        var parent = new unordered_map<int, int>();
        var candidates = new List<int[]>();
        foreach (var edge in edges) {
            if (parent.count(edge[1])) {
                candidates.push_back(new int[] { parent[edge[1]], edge[1] });
                candidates.push_back(edge);
            } else {
                parent[edge[1]] = edge[0];
            }
        }
        int root = Orbit(1, parent).Node;
        if (candidates.size() == 0) {
            var cycle = Orbit(root, parent).Seen;
            foreach (var edge in edges) {
                if (cycle.Contains(edge[0]) && cycle.Contains(edge[1])) {
                    return edge;
                }
            }
        }
        var children = parent.GroupBy(kvp => kvp.Value).ToDictionary(g => g.Key, g => g.Select(kvp => kvp.Key).ToList());
        var seen = new bool[N + 1];
        var stack = new stack<int>();
        stack.push(root);
        while (stack.size() > 0) {
            int node = stack.pop();
            if (!seen[node]) {
                seen[node] = true;
                if (children.count(node)) {
                    foreach (int c in children[node]) stack.push(c);
                }
            }
        }
        return seen.Any(b => !b) ? candidates[0] : candidates[1];
    }
    public class OrbitResult {
        public int Node { get; }
        public HashSet<int> Seen { get; }
        public OrbitResult(int node, HashSet<int> seen) {
            Node = node;
            Seen = seen;
        }
    }
    public OrbitResult Orbit(int node, unordered_map<int, int> parent) {
        var seen = new HashSet<int>();
        while (parent.count(node) && !seen.Contains(node)) {
            seen.push_back(node);
            node = parent[node];
        }
        return new OrbitResult(node, seen);
    }
}

Java Lösung

zugeordnet/original
class Solution {
    public int[] findRedundantDirectedConnection(int[][] edges) {
        int N = edges.length;
        Map<Integer, Integer> parent = new HashMap<>();
        List<int[]> candidates = new ArrayList<>();
        for (int[] edge : edges) {
            if (parent.containsKey(edge[1])) {
                candidates.add(new int[]{parent.get(edge[1]), edge[1]});
                candidates.add(edge);
            } else {
                parent.put(edge[1], edge[0]);
            }
        }

        int root = orbit(1, parent).node;
        if (candidates.isEmpty()) {
            Set<Integer> cycle = orbit(root, parent).seen;
            for (int[] edge : edges) {
                if (cycle.contains(edge[0]) && cycle.contains(edge[1])) {
                    return edge;
                }
            }
        }

        Map<Integer, List<Integer>> children = new HashMap<>();
        for (int v : parent.keySet()) {
            int pv = parent.get(v);
            children.computeIfAbsent(pv, k -> new ArrayList<>()).add(v);
        }

        boolean[] seen = new boolean[N + 1];
        Stack<Integer> stack = new Stack<>();
        stack.add(root);
        while (!stack.isEmpty()) {
            int node = stack.pop();
            if (!seen[node]) {
                seen[node] = true;
                if (children.containsKey(node)) {
                    stack.addAll(children.get(node));
                }
            }
        }
        for (boolean b : seen) {
            if (!b) {
                return candidates.get(0);
            }
        }
        return candidates.get(1);
    }

    public OrbitResult orbit(int node, Map<Integer, Integer> parent) {
        Set<Integer> seen = new HashSet<>();
        while (parent.containsKey(node) && !seen.contains(node)) {
            seen.add(node);
            node = parent.get(node);
        }
        return new OrbitResult(node, seen);
    }
}

class OrbitResult {
    int node;
    Set<Integer> seen;
    OrbitResult(int n, Set<Integer> s) {
        node = n;
        seen = s;
    }
}

Go Lösung

zugeordnet/original
package main

type Solution struct{}

func (s *Solution) findRedundantDirectedConnection(edges [][]int) []int {
    N := len(edges)
    parent := make(map[int]int)
    var candidates [][]int
    for _, edge := range edges {
        if p, exists := parent[edge[1]]; exists {
            candidates = append(candidates, []int{p, edge[1]})
            candidates = append(candidates, edge)
        } else {
            parent[edge[1]] = edge[0]
        }
    }

    root := s.orbit(1, parent).node
    if len(candidates) == 0 {
        cycle := s.orbit(root, parent).seen
        ans := []int{0, 0}
        for _, edge := range edges {
            if cycle[edge[0]] && cycle[edge[1]] {
                ans = edge
            }
        }
        return ans
    }

    children := make(map[int][]int)
    for v, pv := range parent {
        children[pv] = append(children[pv], v)
    }

    seen := make([]bool, N+1)
    seen[0] = true
    stack := []int{root}
    for len(stack) > 0 {
        node := stack[len(stack)-1]
        stack = stack[:len(stack)-1]
        if !seen[node] {
            seen[node] = true
            for _, c := range children[node] {
                stack = append(stack, c)
            }
        }
    }
    for _, b := range seen {
        if !b {
            return candidates[0]
        }
    }
    return candidates[1]
}

type OrbitResult struct {
    node int
    seen map[int]bool
}

func (s *Solution) orbit(node int, parent map[int]int) *OrbitResult {
    seen := make(map[int]bool)
    for {
        if _, exists := parent[node]; !exists || seen[node] {
            break
        }
        seen[node] = true
        node = parent[node]
    }
    return &OrbitResult{node, seen}
}

Algorithm

Сначала создаем базовый Graph, отслеживая ребра, идущие от узлов с несколькими родителями. В итоге у нас будет либо 2, либо 0 кандидатов на удаление ребра.

Если кандидатов нет, то каждый узел имеет одного родителя, как в случае 1->2->3->4->1->5. От любого узла идем к его родителю, пока не посетим узел повторно — тогда мы окажемся внутри цикла, и любые последующие посещенные узлы будут частью этого цикла. В этом случае удаляем последнее edge, Eingabeящее в цикл.

Если есть кандидаты, проверяем, является ли Graph, созданный из родителей, корневым Baumм. Идем от любого узла к его родителю, пока это возможно, затем выполняем обход в глубину (DFS) от этого корня. Если посещаем каждый узел, удаление последнего из двух кандидатов приемлемо. В противном случае удаляем первое из двух ребер-кандидатов.

😎

Stellen zu dieser Aufgabe

aktive Stellen with overlapping task tags are angezeigt.

Alle Stellen
Es gibt noch keine aktiven Stellen.