N Queens Problem in DSA Python - Time & Space Complexity
We want to understand how the time needed to solve the N Queens problem grows as the board size increases.
Specifically, how does the number of steps change when we try to place queens on larger boards?
Analyze the time complexity of the following code snippet.
def solve_n_queens(board, row, n):
if row == n:
return True
for col in range(n):
if is_safe(board, row, col, n):
board[row][col] = 1
if solve_n_queens(board, row + 1, n):
return True
board[row][col] = 0
return False
# is_safe checks if placing a queen is safe
This code tries to place queens row by row, checking safe positions and backtracking if needed.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The recursive calls that try placing a queen in each column of a row.
- How many times: For each row, it tries up to n columns, and for each placement, it recurses to the next row.
As the board size n grows, the number of ways to try placing queens grows very fast.
| Input Size (n) | Approx. Operations |
|---|---|
| 4 | ~256 tries |
| 8 | ~16,777,216 tries |
| 12 | ~8.9 trillion tries |
Pattern observation: The tries grow roughly like n to the power of n, which means the work grows very fast as n increases.
Time Complexity: O(n!)
This means the time needed grows very fast, roughly like n factorial, making it very costly for large boards.
[X] Wrong: "The algorithm only tries n times because it places one queen per row."
[OK] Correct: Actually, it tries many combinations because it explores all columns for each row and backtracks, leading to an exponential number of tries.
Understanding this complexity helps you explain why backtracking can be slow and when to expect such growth in recursive search problems.
"What if we used a heuristic to skip unsafe columns early? How would the time complexity change?"
Practice
N Queens Problem?Solution
Step 1: Understand the problem statement
The N Queens Problem requires placing N queens on an NxN board so that no two queens threaten each other.Step 2: Analyze the options
Only Place N queens on an NxN chessboard so that no two queens attack each other correctly describes placing queens so none attack each other. Other options describe unrelated tasks.Final Answer:
Place N queens on an NxN chessboard so that no two queens attack each other -> Option AQuick Check:
Goal = Place queens safely [OK]
- Thinking queens can be in the same row or column
- Confusing the problem with counting queens
- Assuming queens can attack each other
n?Solution
Step 1: Understand board initialization
We need a 2D list with independent rows to represent the chessboard.Step 2: Analyze each option
board = [[0]*n]*n creates rows referencing the same list, causing bugs. board = [[0 for _ in range(n)] for _ in range(n)] creates independent rows correctly. board = [0]*n creates a 1D list, not 2D. board = [[0]*n] creates a single row only.Final Answer:
board = [[0 for _ in range(n)] for _ in range(n)] -> Option AQuick Check:
Independent rows = board = [[0 for _ in range(n)] for _ in range(n)] [OK]
- Using [[0]*n]*n causing shared references
- Creating 1D list instead of 2D
- Forgetting to repeat for each row
n = 4?
def is_safe(board, row, col):
for i in range(col):
if board[row][i] == 1:
return False
for i, j in zip(range(row, -1, -1), range(col, -1, -1)):
if board[i][j] == 1:
return False
for i, j in zip(range(row, len(board), 1), range(col, -1, -1)):
if board[i][j] == 1:
return False
return True
board = [[0]*4 for _ in range(4)]
board[1][0] = 1
print(is_safe(board, 1, 1))
print(is_safe(board, 0, 1))Solution
Step 1: Check is_safe for position (1,1)
Column check: board[1][0] == 1, so returns False.Step 2: Check is_safe for position (0,1)
Row left: board[0][0] == 0. Upper diagonal: board[0][1] == 0. Lower diagonal: board[1][0] == 1, so returns False.Final Answer:
False\nFalse -> Option BQuick Check:
Check columns and diagonals = False, False [OK]
- Ignoring diagonal checks
- Confusing row and column indices
- Assuming safe if no queen in same row only
def solve_n_queens(board, col):
if col >= len(board):
return True
for row in range(len(board)):
if is_safe(board, row, col):
board[row][col] = 1
if solve_n_queens(board, col + 1):
return True
board[row][col] = 0
return False
board = [[0]*4 for _ in range(4)]
solve_n_queens(board, 0)
print(board)Solution
Step 1: Analyze the recursion and return statements
The function returns True immediately after finding the first solution, so it stops searching further.Step 2: Understand impact on solution finding
This means it finds only one solution and does not explore all possible solutions.Final Answer:
The function returns True too early, missing all solutions -> Option CQuick Check:
Early return stops full search [OK]
- Stopping recursion after first solution
- Not resetting board on backtrack
- Incorrect base case check
Solution
Step 1: Understand efficiency in N Queens
Checking the entire board repeatedly wastes time; pruning reduces checks.Step 2: Analyze options for pruning
Using arrays to track columns and diagonals occupied avoids repeated scanning, improving speed.Final Answer:
Use backtracking with arrays to track columns and diagonals already occupied -> Option DQuick Check:
Pruning with tracking arrays = Use backtracking with arrays to track columns and diagonals already occupied [OK]
- Checking full board every time
- Trying random placements without pruning
- Using brute force without backtracking
Ready to prove it?
Pass the test and this pattern moves unknown
