Create a program that fills in the blank cells in a Sudoku puzzle to solve it.
Every sudoku solution needs to follow to these guidelines:
1) In every row, the numbers 1 through 9 must appear exactly once.
2) In every column, the numbers 1 through 9 must appear exactly once.
3) In each of the grid's nine 3x3 sub-boxes, the numbers 1 through 9 must appear exactly once.
Empty cells are indicated by the '.' character.
To solve a Sudoku puzzle in real life, imagine the task as filling in a partially completed grid so that every row, column, and 3x3 sub-box contains the digits from 1 to 9 exactly once. This involves trial and error, checking for conflicts with existing digits, and backtracking when a conflict arises. Think of it as trying to fit pieces into a jigsaw puzzle, where each piece (digit) must fit perfectly without violating any rules.
Solving this question can be likened to fitting pieces into a jigsaw puzzle where each piece must fit perfectly without violating any rules. In real life, this means filling in the partially completed grid so that every row, column, and 3x3 sub-box contains the digits from 1 to 9 exactly once. This is done through trial and error: identifying empty cells, attempting to place digits, and checking for conflicts. When a conflict arises, backtrack and try a different digit. This process is naturally recursive, as solving the grid involves solving smaller sub-problems (filling in each cell) that depend on previous placements. By treating each empty cell as a sub-problem and recursively attempting to solve the entire grid, the puzzle can be systematically and efficiently solved.
#include<bits/stdc++.h>
using namespace std;
class Solution {
public:
void solveSudoku(vector<vector<char>>& board) {
solve(board);
}
private:
// Recursive method to solve the Sudoku
bool solve(vector<vector<char>>& board) {
// Size of the board
int n = 9;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
// Empty cell found
if (board[i][j] == '.') {
for (char digit = '1'; digit <= '9'; digit++) {
// Check if digit can be placed
if (areRulesMet(board, i, j, digit)) {
// Place digit
board[i][j] = digit;
// Recur to place next digits
if (solve(board)) {
return true;
} else {
// Reset if placing digit doesn't solve Sudoku
board[i][j] = '.';
}
}
}
// If no digit can be placed, return false
return false;
}
}
}
return true; // Sudoku solved
}
// Method to check if placing a digit follows Sudoku rules
bool areRulesMet(vector<vector<char>>& board, int row, int col, char digit) {
for (int i = 0; i < 9; i++) {
if (board[row][i] == digit || board[i][col] == digit) {
// Digit already in row or column
return false;
}
}
int startRow = (row / 3) * 3;
int startCol = (col / 3) * 3;
for (int i = startRow; i < startRow + 3; i++) {
for (int j = startCol; j < startCol + 3; j++) {
if (board[i][j] == digit) {
// Digit already in 3x3 sub-box
return false;
}
}
}
// Digit can be placed
return true;
}
};
int main() {
Solution solution;
vector<vector<char>> board = {
{'5', '3', '.', '.', '7', '.', '.', '.', '.'},
{'6', '.', '.', '1', '9', '5', '.', '.', '.'},
{'.', '9', '8', '.', '.', '.', '.', '6', '.'},
{'8', '.', '.', '.', '6', '.', '.', '.', '3'},
{'4', '.', '.', '8', '.', '3', '.', '.', '1'},
{'7', '.', '.', '.', '2', '.', '.', '.', '6'},
{'.', '6', '.', '.', '.', '.', '2', '8', '.'},
{'.', '.', '.', '4', '1', '9', '.', '.', '5'},
{'.', '.', '.', '.', '8', '.', '.', '7', '9'}
};
solution.solveSudoku(board);
for (const auto& row : board) {
for (char c : row) {
cout << c << " ";
}
cout << endl;
}
return 0;
}
class Solution {
public void solveSudoku(char[][] board) {
solve(board);
}
// Recursive method to solve the Sudoku
private boolean solve(char[][] board) {
int n = 9; // Size of the board
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
// Empty cell found
if (board[i][j] == '.') {
for (char digit = '1'; digit <= '9'; digit++) {
// Check if digit can be placed
if (areRulesMet(board, i, j, digit)) {
// Place digit
board[i][j] = digit;
// Recur to place next digits
if (solve(board)) {
return true;
} else {
// Reset if placing digit doesn't solve Sudoku
board[i][j] = '.';
}
}
}
// If no digit can be placed, return false
return false;
}
}
}
// Sudoku solved
return true;
}
// Method to check if placing a digit follows Sudoku rules
private boolean areRulesMet(char[][] board, int row, int col, char digit) {
for (int i = 0; i < 9; i++) {
if (board[row][i] == digit || board[i][col] == digit) {
// Digit already in row or column
return false;
}
}
int startRow = (row / 3) * 3;
int startCol = (col / 3) * 3;
for (int i = startRow; i < startRow + 3; i++) {
for (int j = startCol; j < startCol + 3; j++) {
if (board[i][j] == digit) {
// Digit already in 3x3 sub-box
return false;
}
}
}
// Digit can be placed
return true;
}
// Main method for testing
public static void main(String[] args) {
Solution solution = new Solution();
char[][] board = {
{'5', '3', '.', '.', '7', '.', '.', '.', '.'},
{'6', '.', '.', '1', '9', '5', '.', '.', '.'},
{'.', '9', '8', '.', '.', '.', '.', '6', '.'},
{'8', '.', '.', '.', '6', '.', '.', '.', '3'},
{'4', '.', '.', '8', '.', '3', '.', '.', '1'},
{'7', '.', '.', '.', '2', '.', '.', '.', '6'},
{'.', '6', '.', '.', '.', '.', '2', '8', '.'},
{'.', '.', '.', '4', '1', '9', '.', '.', '5'},
{'.', '.', '.', '.', '8', '.', '.', '7', '9'}
};
solution.solveSudoku(board);
for (char[] row : board) {
for (char c : row) {
System.out.print(c + " ");
}
System.out.println();
}
}
}
class Solution:
def solveSudoku(self, board):
self.solve(board)
# Recursive method to solve the Sudoku
def solve(self, board):
# Size of the board
n = 9
for i in range(n):
for j in range(n):
# Empty cell found
if board[i][j] == '.':
for digit in '123456789':
# Check if digit can be placed
if self.are_rules_met(board, i, j, digit):
# Place digit
board[i][j] = digit
# Recur to place next digits
if self.solve(board):
return True
else:
# Reset if placing digit doesn't solve Sudoku
board[i][j] = '.'
# If no digit can be placed, return False
return False
# Sudoku solved
return True
# Method to check if placing a digit follows Sudoku rules
def are_rules_met(self, board, row, col, digit):
for i in range(9):
if board[row][i] == digit or board[i][col] == digit:
# Digit already in row or column
return False
start_row, start_col = 3 * (row // 3), 3 * (col // 3)
for i in range(start_row, start_row + 3):
for j in range(start_col, start_col + 3):
if board[i][j] == digit:
# Digit already in 3x3 sub-box
return False
# Digit can be placed
return True
if __name__ == "__main__":
solution = Solution()
board = [
['5', '3', '.', '.', '7', '.', '.', '.', '.'],
['6', '.', '.', '1', '9', '5', '.', '.', '.'],
['.', '9', '8', '.', '.', '.', '.', '6', '.'],
['8', '.', '.', '.', '6', '.', '.', '.', '3'],
['4', '.', '.', '8', '.', '3', '.', '.', '1'],
['7', '.', '.', '.', '2', '.', '.', '.', '6'],
['.', '6', '.', '.', '.', '.', '2', '8', '.'],
['.', '.', '.', '4', '1', '9', '.', '.', '5'],
['.', '.', '.', '.', '8', '.', '.', '7', '9']
]
solution.solveSudoku(board)
for row in board:
print(" ".join(row))
class Solution {
solveSudoku(board) {
this.solve(board);
}
// Recursive method to solve the Sudoku
solve(board) {
const n = 9;
for (let i = 0; i < n; i++) {
for (let j = 0; j < n; j++) {
// Empty cell found
if (board[i][j] === '.') {
for (let digit = '1'; digit <= '9'; digit++) {
// Check if digit can be placed
if (this.areRulesMet(board, i, j, digit)) {
// Place digit
board[i][j] = digit;
if (this.solve(board)) {
// Recur to place next digits
return true;
} else {
// Reset if placing digit doesn't solve Sudoku
board[i][j] = '.';
}
}
}
// If no digit can be placed, return false
return false;
}
}
}
// Sudoku solved
return true;
}
// Method to check if placing a digit follows Sudoku rules
areRulesMet(board, row, col, digit) {
for (let i = 0; i < 9; i++) {
if (board[row][i] === digit || board[i][col] === digit) {
// Digit already in row or column
return false;
}
}
const startRow = Math.floor(row / 3) * 3;
const startCol = Math.floor(col / 3) * 3;
for (let i = startRow; i < startRow + 3; i++) {
for (let j = startCol; j < startCol + 3; j++) {
if (board[i][j] === digit) {
// Digit already in 3x3 sub-box
return false;
}
}
}
// Digit can be placed
return true;
}
}
// Example usage
const board = [
['5', '3', '.', '.', '7', '.', '.', '.', '.'],
['6', '.', '.', '1', '9', '5', '.', '.', '.'],
['.', '9', '8', '.', '.', '.', '.', '6', '.'],
['8', '.', '.', '.', '6', '.', '.', '.', '3'],
['4', '.', '.', '8', '.', '3', '.', '.', '1'],
['7', '.', '.', '.', '2', '.', '.', '.', '6'],
['.', '6', '.', '.', '.', '.', '2', '8', '.'],
['.', '.', '.', '4', '1', '9', '.', '.', '5'],
['.', '.', '.', '.', '8', '.', '.', '7', '9']
];
const solution = new Solution();
solution.solveSudoku(board);
console.log(board.map(row => row.join(' ')).join('\n'));
Time Complexity : O(9^(N*N)), as each cell can be filled with 1 to 9 digits and there are n*n cells.
Space Complexity O(n), where n is the depth of the recursion stack.
Q: Why use backtracking for solving Sudoku?
A: Backtracking systematically explores all possible configurations, ensuring that the solution satisfies all constraints. It is efficient for problems like Sudoku, where the solution space can be pruned early.
Q: How do you handle invalid Sudoku boards?
A: Validate the board before solving by checking for duplicates in rows, columns, and sub-grids. If invalid, return an appropriate error or flag.
Q: What if only partial solutions are required (e.g., fill one cell)?
A: Modify the backtracking function to terminate after finding the first valid number for the target cell.
Q: Can the algorithm be parallelized?
A: Parallelizing backtracking is challenging due to its sequential nature. However, independent sub-grids can be solved in parallel for puzzles with partial constraints.