{x}
blog image

Sudoku Solver

Write a program to solve a Sudoku puzzle by filling the empty cells.

A sudoku solution must satisfy all of the following rules:

  1. Each of the digits 1-9 must occur exactly once in each row.
  2. Each of the digits 1-9 must occur exactly once in each column.
  3. Each of the digits 1-9 must occur exactly once in each of the 9 3x3 sub-boxes of the grid.

The '.' character indicates empty cells.

 

Example 1:

Input: 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"]]
Output: [["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"]]
Explanation: The input board is shown above and the only valid solution is shown below:


 

Constraints:

  • board.length == 9
  • board[i].length == 9
  • board[i][j] is a digit or '.'.
  • It is guaranteed that the input board has only one solution.

Solution Explanation: Sudoku Solver

This problem requires solving a Sudoku puzzle using backtracking. The core idea is to recursively try filling in empty cells with valid numbers, backtracking when a conflict arises.

Approach:

  1. Data Structures: We use three boolean arrays: row, col, and box to track whether a digit is already present in a row, column, and 3x3 subgrid respectively. These arrays significantly optimize checking for valid placements.

  2. Backtracking (DFS): The dfs function implements a depth-first search (DFS) to explore possible solutions.

    • It iterates through empty cells (t list stores coordinates).
    • For each empty cell, it iterates through digits (1-9).
    • Validity Check: Before placing a digit, it verifies if the digit is valid using row, col, and box arrays.
    • Recursive Call: If a digit is valid, it's placed (board updated), and dfs recursively calls itself to continue filling the next empty cell.
    • Backtracking: If a recursive call fails (no solution found), the placed digit is removed (backtracking), and the next digit is tried.
    • Solution Found: If all cells are filled (k == len(t)), a solution is found, ok is set to true, and the function returns.
  3. Initialization:

    • Initially, row, col, and box are filled with False representing empty.
    • The t list stores the coordinates of empty cells.
    • Pre-filled cells are marked in row, col, and box to avoid redundant checks.

Time Complexity: O(9m), where 'm' is the number of empty cells. In the worst case, we might need to explore all possible combinations of digits for empty cells. Since there are at most 81 cells, the worst-case complexity could be considered O(981), though this is highly unlikely in practice due to constraints and Sudoku rules.

Space Complexity: O(m + n2), where 'm' is the number of empty cells (for t list), and 'n' is the size of the board (9 in this case) for the row, col, and box arrays which are of O(n2) space each.

Code Implementation (Python):

class Solution:
    def solveSudoku(self, board: List[List[str]]) -> None:
        row = [[False] * 9 for _ in range(9)]
        col = [[False] * 9 for _ in range(9)]
        box = [[[False] * 9 for _ in range(3)] for _ in range(3)]
        t = []
        ok = False
 
        for i in range(9):
            for j in range(9):
                if board[i][j] == '.':
                    t.append((i, j))
                else:
                    v = int(board[i][j]) - 1
                    row[i][v] = col[j][v] = box[i // 3][j // 3][v] = True
 
        def dfs(k):
            nonlocal ok
            if k == len(t):
                ok = True
                return
            i, j = t[k]
            for v in range(9):
                if not (row[i][v] or col[j][v] or box[i // 3][j // 3][v]):
                    row[i][v] = col[j][v] = box[i // 3][j // 3][v] = True
                    board[i][j] = str(v + 1)
                    dfs(k + 1)
                    row[i][v] = col[j][v] = box[i // 3][j // 3][v] = False
                if ok:
                    return
 
        dfs(0)

Other languages (Java, C++, Go, C#, PHP) follow a similar structure, adapting data structures and syntax according to the language specifics. The core backtracking algorithm remains consistent across all implementations.