#2392 Build a Matrix With Conditions
frequently reported atGoogle
the problem
In plain words
Place the numbers 1..k in a k × k matrix (other cells 0). rowConditions[i] = [above, below] means above's row is strictly above below's row; colConditions[i] = [left, right] means left's column is strictly left of right's. Return any valid matrix, or an empty matrix if impossible.
in k = 3, rowConditions = [[1,2],[3,2]], colConditions = [[2,1],[3,2]]
out [[3,0,0],[0,0,1],[0,2,0]]
in k = 3, rowConditions = [[1,2],[2,3],[3,1],[2,3]], colConditions = [[2,1]]
out []
1 above 2 above 3 above 1 — a cycle.
- 2 ≤ k ≤ 400
- 1 ≤ rowConditions.length, colConditions.length ≤ 10⁴
- above ≠ below, left ≠ right
- 1 ≤ values ≤ k
your turn
Try it before you peek
Read the examples, say the brute force out loud, then write code: here or on LeetCode ↗. Stuck for 20 minutes? Open one hint at a time.
Solve it in the browser
LeetCode-style: complete the class. Compiled by the real javac (Java 17) and judged right here — nothing is sent anywhere.
Solutions are hidden so you can try first. Even 20 minutes of real effort makes the answer stick far better than reading it.
Marking the problem solved, or opening every hint, also shows it.
the aha
Key insight
patternTopological sort & cycle detection
Rows and columns don't interact. Topologically sort the row rules to get each number's row, sort the column rules to get its column, and put each number in its own row and column.
solutions
From brute force to optimal
Reverse post-order DFS on each condition graph gives each value's position.
- DFS-colour each graph; a back edge → return [].
- pos[v] = index in reversed post-order.
- matrix[rowPos[v]][colPos[v]] = v.
Two DFS passes over k vertices and R / C edges, plus filling the k × k output.
Adjacency lists and colours (the k² output is required).
class Solution { public int[][] buildMatrix(int k, int[][] rowConditions, int[][] colConditions) { int[] rowPos = positions(k, rowConditions); int[] colPos = positions(k, colConditions); if (rowPos == null || colPos == null) return new int[0][0]; int[][] matrix = new int[k][k]; for (int v = 1; v <= k; v++) matrix[rowPos[v]][colPos[v]] = v; return matrix; } /** pos[v] = index of v in a topological order (reverse post-order), or null on a cycle. */ private int[] positions(int k, int[][] conditions) { List<List<Integer>> adj = new ArrayList<>(); for (int i = 0; i <= k; i++) adj.add(new ArrayList<>()); for (int[] c : conditions) adj.get(c[0]).add(c[1]); int[] color = new int[k + 1]; List<Integer> post = new ArrayList<>(); for (int v = 1; v <= k; v++) if (color[v] == 0 && !dfs(v, adj, color, post)) return null; int[] pos = new int[k + 1]; for (int i = 0; i < k; i++) pos[post.get(i)] = k - 1 - i; // reversed post-order return pos; } private boolean dfs(int u, List<List<Integer>> adj, int[] color, List<Integer> post) { color[u] = 1; for (int v : adj.get(u)) { if (color[v] == 1) return false; if (color[v] == 0 && !dfs(v, adj, color, post)) return false; } color[u] = 2; post.add(u); return true; }}Same plan with Kahn: the position in Kahn's output is the row (or column).
- rowOrder = kahn(rowConditions), colOrder = kahn(colConditions).
- Either empty → return [].
- rowOf[v], colOf[v] from the orders; place each v.
Two O(k + edges) Kahn passes, plus O(k²) to create the matrix.
Adjacency lists, in-degrees, queues (plus the required output).
class Solution { public int[][] buildMatrix(int k, int[][] rowConditions, int[][] colConditions) { int[] rowOrder = topo(k, rowConditions); int[] colOrder = topo(k, colConditions); if (rowOrder.length == 0 || colOrder.length == 0) return new int[0][0]; // a cycle somewhere int[] rowOf = new int[k + 1], colOf = new int[k + 1]; for (int i = 0; i < k; i++) { rowOf[rowOrder[i]] = i; colOf[colOrder[i]] = i; } int[][] matrix = new int[k][k]; for (int v = 1; v <= k; v++) matrix[rowOf[v]][colOf[v]] = v; // rows and columns are independent return matrix; } /** Kahn on values 1..k; edge {above, below} or {left, right}. Returns [] on a cycle. */ private int[] topo(int k, int[][] conditions) { List<List<Integer>> adj = new ArrayList<>(); for (int i = 0; i <= k; i++) adj.add(new ArrayList<>()); int[] indegree = new int[k + 1]; for (int[] c : conditions) { adj.get(c[0]).add(c[1]); indegree[c[1]]++; } Deque<Integer> queue = new ArrayDeque<>(); for (int v = 1; v <= k; v++) if (indegree[v] == 0) queue.offer(v); int[] order = new int[k]; int idx = 0; while (!queue.isEmpty()) { int u = queue.poll(); order[idx++] = u; for (int v : adj.get(u)) if (--indegree[v] == 0) queue.offer(v); } return idx == k ? order : new int[0]; }}in the room
How to say it in the interview
talk track
- Decouple: "Row constraints only care about rows, column constraints only about columns — two independent topological sorts."
- Every number gets a distinct row and a distinct column, so no two numbers collide.
- Duplicate conditions are fine with Kahn as long as adjacency and in-degree count them the same way.
traps
- Trying to search for placements cell by cell — exponential and unnecessary.
- Forgetting values 1..k are 1-based: size arrays k + 1.
what they ask next
Follow-ups
What about a number that appears in no condition?
Its in-degree is 0, so Kahn outputs it anyway. It still gets its own row and its own column.
How do you know it's impossible?
Kahn's output has fewer than k numbers. The missing ones sit on (or after) a cycle in that condition list, so return an empty matrix.
before you submit
Edge cases to test
- A cycle in only one of the two lists → empty matrix.
- Duplicate conditions: count them the same way in adjacency and in-degree.
- Values are 1..k: size the arrays k + 1.
practise next
Similar problems
- #210Course Schedule IIMediumin Topo Sort
- #269Alien DictionaryHardin Topo SortLeetCode Premium