Learnitweb

LeetCode 1203 — Sort Items by Groups Respecting Dependencies

This is a challenging problem involving topological sorting, grouping, and dependency ordering.

You are given:

  • n items labeled from 0 to n-1
  • Each item belongs to a group (group ID)
  • Some items have prerequisites (beforeItems)
  • You must return a valid ordering of all items such that:
    1. All dependency rules are satisfied
    2. Items from the same group appear together

If no valid ordering exists, return an empty list.

Example:

Input:
n = 8
m = 2
group = [-1,-1,1,0,0,1,0,-1]
beforeItems = [
  [],[6],[5],[6],[3,6],[],[],[]
]

Output:
[6,3,4,5,2,0,7,1]

Problem Understanding

Key details:

  • Items may depend on other items
  • Items are partitioned into groups
  • Items with dependencies in other groups affect group ordering
  • Items with -1 group must be treated as unique new groups

So ordering constraints exist at two levels:

1. Between groups

If any item in group A depends on an item in group B,
then group B must come before group A

2. Within each group

Items must follow dependency order inside their group

This means two topological sorts are needed:

✅ one for groups
✅ one for items


Logic Explained in Simple English

To solve this problem, think in these steps:

Step A: Normalize group assignments

  • Items with group = -1 must be treated as belonging to their own new group

Why?
Because they must not mix with other groups.

Step B: Build two dependency graphs:

1. Item graph

  • Standard dependency graph
  • Edges: prerequisite → dependent item

2. Group graph

  • If item X depends on item Y and they have different groups:
    • Add edge from group(Y) → group(X)

Step C: Topologically sort the groups

  • If impossible → return empty result

Step D: Topologically sort items within their groups

  • But maintain group ordering from Step C

Step E: Assemble final result

  • Output items grouped in sorted group order
  • Preserve item order inside each group

This ensures:

  • All dependencies respected
  • Groups stay in contiguous blocks

Step-by-Step Solution Approach

  1. Assign new group IDs to ungrouped items
  2. Create:
    • groupGraph and group in-degrees
    • itemGraph and item in-degrees
  3. For each dependency:
    • Always update item graph
    • If groups differ, update group graph
  4. Topo sort the group graph
  5. Topo sort the item graph
  6. Bucket items into their groups based on item topo order
  7. Output items following sorted group order

Java Implementation

class Solution {

    public List<Integer> sortItems(int n, int m, int[] group, List<List<Integer>> beforeItems) {

        // Step 1: assign new group IDs to ungrouped items
        int newGroupId = m;
        for (int i = 0; i < n; i++) {
            if (group[i] == -1) {
                group[i] = newGroupId++;
            }
        }

        int totalGroups = newGroupId;

        // Step 2: build graphs
        List<List<Integer>> groupGraph = new ArrayList<>();
        List<List<Integer>> itemGraph = new ArrayList<>();

        for (int i = 0; i < totalGroups; i++) {
            groupGraph.add(new ArrayList<>());
        }
        for (int i = 0; i < n; i++) {
            itemGraph.add(new ArrayList<>());
        }

        int[] groupIndegree = new int[totalGroups];
        int[] itemIndegree = new int[n];

        // Step 3: build edges
        for (int i = 0; i < n; i++) {
            for (int before : beforeItems.get(i)) {
                itemGraph.get(before).add(i);
                itemIndegree[i]++;

                if (group[before] != group[i]) {
                    groupGraph.get(group[before]).add(group[i]);
                    groupIndegree[group[i]]++;
                }
            }
        }

        // Step 4: topological sort for groups
        List<Integer> groupOrder = topoSort(groupGraph, groupIndegree, totalGroups);
        if (groupOrder.isEmpty()) return new ArrayList<>();

        // Step 5: topological sort for items
        List<Integer> itemOrder = topoSort(itemGraph, itemIndegree, n);
        if (itemOrder.isEmpty()) return new ArrayList<>();

        // Step 6: bucket items by group
        Map<Integer, List<Integer>> groupedItems = new HashMap<>();
        for (int g : groupOrder) {
            groupedItems.put(g, new ArrayList<>());
        }

        for (int item : itemOrder) {
            groupedItems.get(group[item]).add(item);
        }

        // Step 7: assemble final result
        List<Integer> result = new ArrayList<>();
        for (int g : groupOrder) {
            result.addAll(groupedItems.get(g));
        }

        return result;
    }

    private List<Integer> topoSort(List<List<Integer>> graph, int[] indegree, int size) {
        Queue<Integer> queue = new LinkedList<>();
        List<Integer> order = new ArrayList<>();

        for (int i = 0; i < size; i++) {
            if (indegree[i] == 0) queue.add(i);
        }

        while (!queue.isEmpty()) {
            int node = queue.poll();
            order.add(node);

            for (int neighbor : graph.get(node)) {
                indegree[neighbor]--;
                if (indegree[neighbor] == 0) {
                    queue.add(neighbor);
                }
            }
        }

        return order.size() == size ? order : new ArrayList<>();
    }
}

Dry Run Example (High Level)

Input:

n = 4, m = 1
group = [0,0,1,1]
beforeItems:
0: []
1: [0]
2: [1]
3: []

Step 1 — No -1 groups, skip assigning

Step 2 — Build graphs

Item dependencies:

0 → 1
1 → 2

Groups:

group(0)=0, group(1)=0 → same group
group(1)=0, group(2)=1 → group edge 0 → 1

Step 3 — Toposort groups

Order:

[0, 1]

Step 4 — Toposort items

Order:

[0,1,2,3]

Step 5 — Bucket items:

Group 0: [0,1]
Group 1: [2,3]

Final Output:

[0,1,2,3]

Time and Space Complexity

Time Complexity

O(n + totalDependencies)

Because:

  • Building graphs takes linear time
  • Two topo sorts take linear time

Space Complexity

O(n + totalDependencies)

Graph storage and output


Common Mistakes and How to Avoid Them

Mistake 1: Only sorting items

Group dependencies matter.

Mistake 2: Not creating separate groups for -1 items

Those items must not mix arbitrarily.

Mistake 3: Forgetting two-level topo sorting

One level alone cannot satisfy constraints.

Mistake 4: Returning result too early

Must check cycles in both graphs.

Mistake 5: Assuming dependencies imply item-level only

Group ordering is required too.