This problem asks us to sort items while satisfying two constraints at the same time. First, there are explicit ordering dependencies: some items must appear before others, as given by beforeItems. Second, there is a grouping constraint: all items belonging to the same group must be adjacent in the final ordering.
A useful analogy is scheduling tasks for different teams in a company. Each task may depend on other tasks finishing first, and each team's tasks should sit together in the schedule so the team works in one focused block. We need a single ordering that respects both the dependencies and the grouping requirement.
This is two topological sort problems stacked on top of each other. We need to figure out two things: what order the group blocks appear in, and within each group block, what order the items appear in. If any item A in group X must come before item B in group Y, then group X's block must appear before group Y's block. Both levels of ordering can be computed with topological sort, and if either level has a cycle, no valid answer exists.
1 <= m <= n <= 3 * 10^4 -> With up to 30,000 items, we need an approach that runs in roughly O(n + E) time, where E is the total number of dependency edges. Anything quadratic is risky.0 <= beforeItems[i].length <= n - 1 -> Each item can depend on up to n-1 others. The total number of edges across all items could be O(n^2) in the worst case, though typical inputs are much sparser.group[i] == -1 means the item belongs to no group -> These ungrouped items need special handling. Since they do not need to be adjacent to anything, they can be placed freely as long as dependencies are satisfied.One starting point is to ignore the grouping constraint and run a regular topological sort on all items using the beforeItems dependencies. Topological sort produces a valid ordering where every dependency is respected, so that constraint is handled.
This ordering has no reason to keep items from the same group together. For example, if items 2 and 5 are in group 1, the topological sort might produce something like [..., 2, ..., 3, 4, ..., 5, ...] with items from other groups placed between 2 and 5. That violates the grouping constraint.
Rearranging the result afterward to pull group members next to each other can break the dependency ordering. If item 3 (group 0) must come before item 5 (group 1), and item 2 (group 1) must come after some item that itself comes after 3, then moving 2 next to 5 might place 2 before 3 and violate a dependency.
A single-level topological sort has no mechanism to enforce grouping.
beforeItems dependencies.Step 4 is the obstacle: rearranging while preserving dependencies is the original problem again, not a simpler subproblem. A standard topological sort orders items by dependencies alone, with no way to express "keep these items together." The fix is to sort at two levels, first ordering the groups relative to each other, then ordering the items within each group.
Decompose the problem into two separate topological sorts. The final output is a sequence of group blocks, where each block contains all items from one group in some order. Two decisions remain: what order the group blocks appear in, and within each block, what order the items appear in.
Both orderings come from the beforeItems dependencies. If item A (in group X) must come before item B (in group Y, where X != Y), then group X's block must come before group Y's block entirely. If A and B are both in the same group, then A must come before B within that group's block.
So we build two graphs: a group-level graph where edges represent "group X must come before group Y" relationships derived from cross-group item dependencies, and an item-level graph where edges represent the original beforeItems dependencies, used for within-group sorting.
For ungrouped items (where group[i] == -1), assign each one its own unique virtual group of size 1. A group with one item satisfies the adjacency requirement automatically, which removes the special case.
Every cross-group dependency A -> B becomes a group edge group(A) -> group(B), so the group sort places all of group(A) before all of group(B). Since each group is emitted as one contiguous block, the cross-group dependency holds for every pair of items in those two groups, not only A and B. Within a single group, the item-level sort enforces the remaining same-group dependencies. A cycle at either level means no ordering satisfies the dependencies, and the sort reports failure by leaving nodes unprocessed.
group[i] == -1, assign group[i] = nextGroupId++ starting from m. Track the total number of groups.i and each predecessor p in beforeItems[i], add edge p -> i to the item graph. If group[p] != group[i], also add edge group[p] -> group[i] to the group graph (with deduplication).