🧠
Brute Force (Cycle Detection with DFS + Naive Positioning)
💡 Starting with brute force helps understand the problem's core: verifying if the given conditions form valid orderings and then trying to place elements accordingly, even if inefficient.
Intuition
Try to build the orderings by checking for cycles using DFS in both row and column conditions. If no cycles, assign positions based on the order found. This approach is straightforward but not optimized for large inputs.
Algorithm
- Build adjacency lists for rowConditions and colConditions.
- Use DFS to detect cycles and generate topological order for rows and columns.
- If a cycle is detected in either, return empty matrix.
- Assign each number a row and column index based on the topological orderings.
- Construct the matrix placing each number at its assigned row and column.
💡 The challenge is to understand how to detect cycles and produce a valid ordering, then map that ordering to matrix positions.
from collections import defaultdict
import sys
sys.setrecursionlimit(10**7)
def build_graph(conditions, n):
graph = defaultdict(list)
for u, v in conditions:
graph[u].append(v)
return graph
def dfs(node, graph, visited, stack):
if visited[node] == 1: # visiting
return False
if visited[node] == 2: # visited
return True
visited[node] = 1
for nei in graph[node]:
if not dfs(nei, graph, visited, stack):
return False
visited[node] = 2
stack.append(node)
return True
def topological_sort(conditions, n):
graph = build_graph(conditions, n)
visited = [0] * (n + 1)
stack = []
for node in range(1, n + 1):
if visited[node] == 0:
if not dfs(node, graph, visited, stack):
return []
stack.reverse()
return stack
def buildMatrix(n, rowConditions, colConditions):
row_order = topological_sort(rowConditions, n)
if not row_order:
return []
col_order = topological_sort(colConditions, n)
if not col_order:
return []
pos_in_row = {num: i for i, num in enumerate(row_order)}
pos_in_col = {num: i for i, num in enumerate(col_order)}
matrix = [[0] * n for _ in range(n)]
for num in range(1, n + 1):
r = pos_in_row[num]
c = pos_in_col[num]
matrix[r][c] = num
return matrix
# Driver code
if __name__ == '__main__':
n = 3
rowConditions = [[1,2],[2,3]]
colConditions = [[2,1],[3,2]]
result = buildMatrix(n, rowConditions, colConditions)
for row in result:
print(row)
Line Notes
def build_graph(conditions, n):Helper to create adjacency list from conditions to represent dependencies
for u, v in conditions:Add directed edges from u to v indicating u must come before v
def dfs(node, graph, visited, stack):DFS function to detect cycles and build topological order
if visited[node] == 1:If node is currently being visited, a cycle is detected
stack.append(node)Add node to stack after visiting all descendants to build order
def topological_sort(conditions, n):Perform topological sort or return empty if cycle detected
for node in range(1, n + 1):Visit all nodes including isolated ones to ensure full ordering
row_order = topological_sort(rowConditions, n)Get row ordering or empty if invalid due to cycle
pos_in_row = {num: i for i, num in enumerate(row_order)}Map each number to its row index for placement
matrix = [[0] * n for _ in range(n)]Initialize empty n x n matrix with zeros
matrix[r][c] = numPlace number at its assigned row and column position in matrix
import java.util.*;
public class BuildMatrix {
private static Map<Integer, List<Integer>> buildGraph(int[][] conditions, int n) {
Map<Integer, List<Integer>> graph = new HashMap<>();
for (int i = 1; i <= n; i++) graph.put(i, new ArrayList<>());
for (int[] cond : conditions) {
graph.get(cond[0]).add(cond[1]);
}
return graph;
}
private static boolean dfs(int node, Map<Integer, List<Integer>> graph, int[] visited, List<Integer> stack) {
if (visited[node] == 1) return false; // cycle
if (visited[node] == 2) return true; // visited
visited[node] = 1;
for (int nei : graph.get(node)) {
if (!dfs(nei, graph, visited, stack)) return false;
}
visited[node] = 2;
stack.add(node);
return true;
}
private static List<Integer> topologicalSort(int[][] conditions, int n) {
Map<Integer, List<Integer>> graph = buildGraph(conditions, n);
int[] visited = new int[n + 1];
List<Integer> stack = new ArrayList<>();
for (int node = 1; node <= n; node++) {
if (visited[node] == 0) {
if (!dfs(node, graph, visited, stack)) return new ArrayList<>();
}
}
Collections.reverse(stack);
return stack;
}
public static int[][] buildMatrix(int n, int[][] rowConditions, int[][] colConditions) {
List<Integer> rowOrder = topologicalSort(rowConditions, n);
if (rowOrder.isEmpty()) return new int[0][0];
List<Integer> colOrder = topologicalSort(colConditions, n);
if (colOrder.isEmpty()) return new int[0][0];
int[] posInRow = new int[n + 1];
int[] posInCol = new int[n + 1];
for (int i = 0; i < n; i++) {
posInRow[rowOrder.get(i)] = i;
posInCol[colOrder.get(i)] = i;
}
int[][] matrix = new int[n][n];
for (int num = 1; num <= n; num++) {
matrix[posInRow[num]][posInCol[num]] = num;
}
return matrix;
}
public static void main(String[] args) {
int n = 3;
int[][] rowConditions = {{1,2},{2,3}};
int[][] colConditions = {{2,1},{3,2}};
int[][] result = buildMatrix(n, rowConditions, colConditions);
for (int[] row : result) {
System.out.println(Arrays.toString(row));
}
}
}
Line Notes
private static Map<Integer, List<Integer>> buildGraph(int[][] conditions, int n)Build adjacency list from conditions to represent dependencies
for (int[] cond : conditions)Add directed edges from cond[0] to cond[1]
private static boolean dfs(int node, Map<Integer, List<Integer>> graph, int[] visited, List<Integer> stack)DFS to detect cycles and build topological order
if (visited[node] == 1) return false;Cycle detected if node is currently being visited
stack.add(node);Add node after visiting all descendants to build order
private static List<Integer> topologicalSort(int[][] conditions, int n)Perform topological sort or return empty list if cycle detected
for (int node = 1; node <= n; node++)Visit all nodes including isolated ones
List<Integer> rowOrder = topologicalSort(rowConditions, n);Get row order or empty if invalid
int[] posInRow = new int[n + 1];Map each number to its row index
matrix[posInRow[num]][posInCol[num]] = num;Place number in matrix at assigned position
#include <bits/stdc++.h>
using namespace std;
unordered_map<int, vector<int>> buildGraph(vector<vector<int>>& conditions, int n) {
unordered_map<int, vector<int>> graph;
for (int i = 1; i <= n; i++) graph[i] = {};
for (auto& cond : conditions) {
graph[cond[0]].push_back(cond[1]);
}
return graph;
}
bool dfs(int node, unordered_map<int, vector<int>>& graph, vector<int>& visited, vector<int>& stack) {
if (visited[node] == 1) return false; // cycle
if (visited[node] == 2) return true; // visited
visited[node] = 1;
for (int nei : graph[node]) {
if (!dfs(nei, graph, visited, stack)) return false;
}
visited[node] = 2;
stack.push_back(node);
return true;
}
vector<int> topologicalSort(vector<vector<int>>& conditions, int n) {
auto graph = buildGraph(conditions, n);
vector<int> visited(n + 1, 0);
vector<int> stack;
for (int node = 1; node <= n; node++) {
if (visited[node] == 0) {
if (!dfs(node, graph, visited, stack)) return {};
}
}
reverse(stack.begin(), stack.end());
return stack;
}
vector<vector<int>> buildMatrix(int n, vector<vector<int>>& rowConditions, vector<vector<int>>& colConditions) {
vector<int> rowOrder = topologicalSort(rowConditions, n);
if (rowOrder.empty()) return {};
vector<int> colOrder = topologicalSort(colConditions, n);
if (colOrder.empty()) return {};
vector<int> posInRow(n + 1), posInCol(n + 1);
for (int i = 0; i < n; i++) {
posInRow[rowOrder[i]] = i;
posInCol[colOrder[i]] = i;
}
vector<vector<int>> matrix(n, vector<int>(n, 0));
for (int num = 1; num <= n; num++) {
matrix[posInRow[num]][posInCol[num]] = num;
}
return matrix;
}
int main() {
int n = 3;
vector<vector<int>> rowConditions = {{1,2},{2,3}};
vector<vector<int>> colConditions = {{2,1},{3,2}};
vector<vector<int>> result = buildMatrix(n, rowConditions, colConditions);
for (auto& row : result) {
for (int val : row) cout << val << ' ';
cout << '\n';
}
return 0;
}
Line Notes
unordered_map<int, vector<int>> buildGraph(vector<vector<int>>& conditions, int n)Create adjacency list from conditions to represent dependencies
for (auto& cond : conditions)Add directed edges from cond[0] to cond[1]
bool dfs(int node, unordered_map<int, vector<int>>& graph, vector<int>& visited, vector<int>& stack)DFS to detect cycles and build topological order
if (visited[node] == 1) return false;Cycle detected if node is currently being visited
stack.push_back(node);Add node after visiting all descendants
vector<int> topologicalSort(vector<vector<int>>& conditions, int n)Perform topological sort or return empty if cycle detected
for (int node = 1; node <= n; node++)Visit all nodes including isolated ones
vector<int> posInRow(n + 1), posInCol(n + 1);Map numbers to row and column indices
matrix[posInRow[num]][posInCol[num]] = num;Place number in matrix at assigned position
function buildGraph(conditions, n) {
const graph = new Map();
for (let i = 1; i <= n; i++) graph.set(i, []);
for (const [u, v] of conditions) {
graph.get(u).push(v);
}
return graph;
}
function dfs(node, graph, visited, stack) {
if (visited[node] === 1) return false; // cycle
if (visited[node] === 2) return true; // visited
visited[node] = 1;
for (const nei of graph.get(node)) {
if (!dfs(nei, graph, visited, stack)) return false;
}
visited[node] = 2;
stack.push(node);
return true;
}
function topologicalSort(conditions, n) {
const graph = buildGraph(conditions, n);
const visited = Array(n + 1).fill(0);
const stack = [];
for (let node = 1; node <= n; node++) {
if (visited[node] === 0) {
if (!dfs(node, graph, visited, stack)) return [];
}
}
stack.reverse();
return stack;
}
function buildMatrix(n, rowConditions, colConditions) {
const rowOrder = topologicalSort(rowConditions, n);
if (rowOrder.length === 0) return [];
const colOrder = topologicalSort(colConditions, n);
if (colOrder.length === 0) return [];
const posInRow = new Array(n + 1);
const posInCol = new Array(n + 1);
for (let i = 0; i < n; i++) {
posInRow[rowOrder[i]] = i;
posInCol[colOrder[i]] = i;
}
const matrix = Array.from({ length: n }, () => Array(n).fill(0));
for (let num = 1; num <= n; num++) {
matrix[posInRow[num]][posInCol[num]] = num;
}
return matrix;
}
// Driver code
const n = 3;
const rowConditions = [[1,2],[2,3]];
const colConditions = [[2,1],[3,2]];
const result = buildMatrix(n, rowConditions, colConditions);
for (const row of result) {
console.log(row);}
Line Notes
function buildGraph(conditions, n)Create adjacency list from conditions to represent dependencies
for (const [u, v] of conditions)Add directed edges from u to v
function dfs(node, graph, visited, stack)DFS to detect cycles and build topological order
if (visited[node] === 1) return false;Cycle detected if node is currently being visited
stack.push(node);Add node after visiting all descendants
function topologicalSort(conditions, n)Perform topological sort or return empty if cycle detected
for (let node = 1; node <= n; node++)Visit all nodes including isolated ones
const posInRow = new Array(n + 1);Map numbers to row indices
matrix[posInRow[num]][posInCol[num]] = num;Place number in matrix at assigned position
TimeO(n + m) where m is total number of conditions
SpaceO(n + m) for graph and recursion stack
We build graphs and run DFS for cycle detection and topological sort on both row and column conditions. Each edge and node is processed once.
💡 For n=1000 and m=2000, this means roughly 3000 operations, which is feasible but can be slow if implemented inefficiently.
Interview Verdict: Accepted but can be slow for very large inputs
This approach works but is not optimal for the largest constraints due to recursion overhead and repeated code.