Skip to content

1203. Sort Items by Groups Respecting Dependencies 👍

  • Time: $O(|V| + |E|)$, where $|V| = n + m$ and $|E| = |\texttt{group[i]}| \ne -1 + |\texttt{items[i]}| \in \texttt{beforeItems}$
  • Space: $O(|V| + |E|)$
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
class Solution {
 public:
  vector<int> sortItems(int n, int m, vector<int>& group,
                        vector<vector<int>>& beforeItems) {
    vector<vector<int>> graph(n + m);
    vector<int> inDegrees(n + m);

    // Build the graph by remapping the k-th group to k + n imaginary node.
    for (int i = 0; i < group.size(); ++i) {
      if (group[i] == -1)
        continue;
      graph[group[i] + n].push_back(i);
      ++inDegrees[i];
    }

    for (int i = 0; i < beforeItems.size(); ++i)
      for (const int b : beforeItems[i]) {
        const int u = group[b] == -1 ? b : group[b] + n;
        const int v = group[i] == -1 ? i : group[i] + n;
        if (u == v) {  // u and v are already in the same group.
          graph[b].push_back(i);
          ++inDegrees[i];
        } else {
          graph[u].push_back(v);
          ++inDegrees[v];
        }
      }

    // Perform topological sorting.
    vector<int> ans;

    for (int i = 0; i < n + m; ++i)
      if (inDegrees[i] == 0)  // inDegrees[i] == -1 means visited.
        dfs(graph, i, inDegrees, n, ans);

    return ans.size() == n ? ans : vector<int>();
  }

 private:
  void dfs(const vector<vector<int>>& graph, int u, vector<int>& inDegrees,
           int n, vector<int>& ans) {
    if (u < n)
      ans.push_back(u);

    inDegrees[u] = -1;  // Mark as visited.

    for (const int v : graph[u])
      if (--inDegrees[v] == 0)
        dfs(graph, v, inDegrees, n, ans);
  }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
class Solution {
  public int[] sortItems(int n, int m, int[] group, List<List<Integer>> beforeItems) {
    List<Integer>[] graph = new List[n + m];
    int[] inDegrees = new int[n + m];

    for (int i = 0; i < graph.length; ++i)
      graph[i] = new ArrayList<>();

    // Build the graph by remapping the k-th group to k + n imaginary node.
    for (int i = 0; i < group.length; ++i) {
      if (group[i] == -1)
        continue;
      graph[group[i] + n].add(i);
      ++inDegrees[i];
    }

    for (int i = 0; i < beforeItems.size(); ++i)
      for (final int b : beforeItems.get(i)) {
        final int u = group[b] == -1 ? b : group[b] + n;
        final int v = group[i] == -1 ? i : group[i] + n;
        if (u == v) { // u and v are already in the same group.
          graph[b].add(i);
          ++inDegrees[i];
        } else {
          graph[u].add(v);
          ++inDegrees[v];
        }
      }

    // Perform topological sorting.
    List<Integer> ans = new ArrayList<>();

    for (int i = 0; i < n + m; ++i)
      if (inDegrees[i] == 0) // inDegrees[i] == -1 means visited.
        dfs(graph, i, inDegrees, n, ans);

    return ans.size() == n ? ans.stream().mapToInt(Integer::intValue).toArray() : new int[] {};
  }

  private void dfs(List<Integer>[] graph, int u, int[] inDegrees, int n, List<Integer> ans) {
    if (u < n)
      ans.add(u);

    inDegrees[u] = -1; // Mark as visited.

    for (final int v : graph[u])
      if (--inDegrees[v] == 0)
        dfs(graph, v, inDegrees, n, ans);
  }
}