Sudoku Solver Using Backtracking in DSA Go - Time & Space Complexity
We want to understand how the time needed to solve a Sudoku puzzle grows as the puzzle size or difficulty changes.
Specifically, we ask: How does the backtracking solver's work increase with more empty cells?
Analyze the time complexity of the following Sudoku solver using backtracking.
func solveSudoku(board [][]byte) bool {
for i := 0; i < 9; i++ {
for j := 0; j < 9; j++ {
if board[i][j] == '.' {
for c := byte('1'); c <= '9'; c++ {
if isValid(board, i, j, c) {
board[i][j] = c
if solveSudoku(board) {
return true
}
board[i][j] = '.'
}
}
return false
}
}
}
return true
}
This code tries digits 1 to 9 in each empty cell, checking if the choice is valid, and uses recursion to fill the next cells.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Trying digits 1 to 9 in each empty cell and recursively solving the rest.
- How many times: Potentially up to 9 choices per empty cell, repeated recursively for all empty cells.
Each empty cell can try up to 9 digits, and for each choice, the solver tries to fill the next empty cell.
| Empty Cells (n) | Approx. Operations |
|---|---|
| 10 | Up to 9^10 (about 3.5 billion) tries |
| 20 | Up to 9^20 (very large, trillions of trillions) |
| 30 | Up to 9^30 (astronomically large) |
Pattern observation: The number of operations grows exponentially with the number of empty cells.
Time Complexity: O(9^n)
This means the time needed can grow very fast as the number of empty cells increases, because each cell tries many possibilities recursively.
[X] Wrong: "The solver only tries each empty cell once, so time is linear in empty cells."
[OK] Correct: The solver tries many digits per cell and backtracks, so it explores many combinations, not just one pass.
Understanding this exponential growth helps you explain why backtracking is powerful but can be slow, and shows your grasp of recursive problem solving.
"What if we added a heuristic to pick the empty cell with the fewest valid digits first? How would the time complexity change?"
Practice
backtracking technique used in a Sudoku solver?Solution
Step 1: Understand backtracking concept
Backtracking tries a number in a cell and moves forward if valid, else it undoes (backtracks) and tries another number.Step 2: Compare options
Only Try placing numbers and undo if they lead to conflicts describes this trial and undo process correctly, others do not represent backtracking.Final Answer:
Try placing numbers and undo if they lead to conflicts -> Option CQuick Check:
Backtracking = Try and undo [OK]
- Thinking backtracking fills randomly without checks
- Assuming backtracking fills only cells with one option
- Confusing backtracking with brute force without undo
Solution
Step 1: Identify required parameters for validity check
We need the board, row, column, and number to check if placing is valid.Step 2: Check return type and parameters
func isValid(board [][]int, row int, col int, num int) bool has correct parameters and returns bool indicating validity. Others miss parameters or have wrong return types.Final Answer:
func isValid(board [][]int, row int, col int, num int) bool -> Option AQuick Check:
Correct params and bool return = func isValid(board [][]int, row int, col int, num int) bool [OK]
- Missing row or col parameters
- Wrong return type like int or string
- Using fixed size array instead of slice
solveSudoku(board)?board := [][]int{
{5,3,0,0,7,0,0,0,0},
{6,0,0,1,9,5,0,0,0},
{0,9,8,0,0,0,0,6,0},
{8,0,0,0,6,0,0,0,3},
{4,0,0,8,0,3,0,0,1},
{7,0,0,0,2,0,0,0,6},
{0,6,0,0,0,0,2,8,0},
{0,0,0,4,1,9,0,0,5},
{0,0,0,0,8,0,0,7,9},
}
solveSudoku(board)
fmt.Println(board)Solution
Step 1: Understand solveSudoku function
It uses backtracking to fill all zeros with valid numbers to complete the Sudoku.Step 2: Check expected output
The function fills all empty cells correctly, so the printed board is the fully solved Sudoku as in [[5 3 4 6 7 8 9 1 2] [6 7 2 1 9 5 3 4 8] [1 9 8 3 4 2 5 6 7] [8 5 9 7 6 1 4 2 3] [4 2 6 8 5 3 7 9 1] [7 1 3 9 2 4 8 5 6] [9 6 1 5 3 7 2 8 4] [2 8 7 4 1 9 6 3 5] [3 4 5 2 8 6 1 7 9]].Final Answer:
Fully solved Sudoku board with no zeros -> Option DQuick Check:
Backtracking solves all zeros = [[5 3 4 6 7 8 9 1 2] [6 7 2 1 9 5 3 4 8] [1 9 8 3 4 2 5 6 7] [8 5 9 7 6 1 4 2 3] [4 2 6 8 5 3 7 9 1] [7 1 3 9 2 4 8 5 6] [9 6 1 5 3 7 2 8 4] [2 8 7 4 1 9 6 3 5] [3 4 5 2 8 6 1 7 9]] [OK]
- Expecting zeros to remain after solve
- Thinking partial fill is output
- Assuming runtime error without index issues
func solve(board [][]int) bool {
for r := 0; r < 9; r++ {
for c := 0; c < 9; c++ {
if board[r][c] == 0 {
for num := 1; num <= 9; num++ {
if isValid(board, r, c, num) {
board[r][c] = num
if solve(board) {
return true
}
board[r][c] = 0
}
}
return false
}
}
}
return true
}Solution
Step 1: Analyze backtracking logic
The code tries numbers 1-9 in empty cells, recurses, and resets cell if no solution found.Step 2: Check for missing returns or resets
It returns false if no number fits, resets cell to zero after backtracking, and loops are correct.Final Answer:
No bug; code is correct -> Option AQuick Check:
Backtracking code with proper returns and resets = No bug; code is correct [OK]
- Forgetting to reset cell to zero after failed try
- Missing return false after trying all numbers
- Using wrong loop limits for rows or columns
Solution
Step 1: Understand optimization needs
Backtracking checks validity repeatedly; tracking used numbers speeds up validity checks.Step 2: Evaluate options
Use additional data structures to track used numbers in rows, columns, and boxes uses extra data structures (like arrays or maps) to quickly check if a number is used in row, column, or box, reducing repeated scans.Final Answer:
Use additional data structures to track used numbers in rows, columns, and boxes -> Option BQuick Check:
Tracking usage reduces checks = Use additional data structures to track used numbers in rows, columns, and boxes [OK]
- Trying numbers randomly without checks
- Ignoring cells outside first row
- Increasing board size which complicates solving
Ready to prove it?
Pass the test and this pattern moves unknown
