Sudoko Solver

Chetan DattaChetan Datta
4 min read

Problem

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

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

Brute force Approach

We iterate through all the elements on the board. If an element is a dot, we check if we can place any number from 1 to 9 in that spot. We start with 1 and check if it’s safe to place it. If not, we move to the next number, and so on. If it’s safe, we place the number and call the solve method again. This process repeats, trying to place numbers in the dots.

When the board is completely filled, we return true, which stops the recursion and confirms that the board has a valid solution. If we can’t fill the first dot, we immediately return false

The key part of filling the board is determining if it’s safe to place a number at index (i, j). We check three things:

  1. The number must not already be present in the current row.

  2. The number must not already be present in the current column.

  3. The number must not be present in the 3x3 square that contains the index (i, j).

In a 9x9 Sudoku matrix, there are 9 squares, each 3x3. To find the first element of the square for a given index (i, j), we calculate the square coordinates: (i/3, j/3).

  • Square Row Index: row_index_of_square = i/3

  • Square Column Index: column_index_of_square = j/3

The first element index of the square in the matrix is (3 x row_index_of_square, 3 x column_index_of_square).

From this first element index, we can iterate through all the elements of the square. There are 9 elements in each square, and a single loop can iterate through them.

Using the first element index of the square, we can iterate through all elements with the formula:

(row_index_of_first_element + i/3, column_index_of_first_index + i%3)

The row index increments by one after every three elements (i/3), and the column index changes with each increment, cycling through 0, 1, and 2 (i%3).

class Solution {
    private boolean solve(char[][] board){

        for(int i=0; i<9; i++){
            for(int j=0; j<9; j++){

                if(board[i][j]=='.'){
                    //try all the elements
                    for(char num='1'; num<='9'; num++){
                        if(isSafe(board, num, i, j)){
                            board[i][j]=num;
                            if(solve(board)) return true;
                            board[i][j] = '.';
                        }
                    }
                    return false;
                }
            }
        }
        return true;
    }
    private boolean isSafe(char[][] board, char num, int row, int col){

        //For iterating the square elements
        int rowIndexOfSquare = row/3;
        int colIndexOfSquare = col/3;
        int rowIndexOfFirstElement = 3 * rowIndexOfSquare;
        int colIndexOfFirstElement = 3 * colIndexOfSquare;

        for(int i=0; i<9; i++){
            if(board[row][i]==num) return false;
            if(board[i][col]==num) return false;

            int xRow = rowIndexOfFirstElement + i/3;
            int yCol = colIndexOfFirstElement + i%3;

            if(board[xRow][yCol]==num) return false;
        }
        return true;
    }

    public void solveSudoku(char[][] board) {
        solve(board);
    }
}

Better Approach

This approach optimizes the brute force method. Instead of starting from the first index (0,0) each time the solve method is called, we pass the current row and column indices to continue checking from that point. When the column index reaches the end, we reset it to 0 and move to the next row, ensuring the iteration continues correctly.

class Solution {
    private boolean solve(char[][] board, int row, int col){

        for(int i=row; i<9; i++){
            for(int j=col; j<9; j++){

                if(board[i][j]=='.'){
                    for(char num='1'; num<='9'; num++){
                        if(isSafe(board, num, i, j)){
                            board[i][j]=num;
                            if(solve(board, i, j)) return true;
                            board[i][j] = '.';
                        }
                    }
                    return false;
                }
            }
            //Important step
            col = 0;
        }
        return true;
    }

    private boolean isSafe(char[][] board, char num, int row, int col){

        //For iterating the square elements
        int rowIndexOfSquare = row/3;
        int colIndexOfSquare = col/3;
        int rowIndexOfFirstElement = 3 * rowIndexOfSquare;
        int colIndexOfFirstElement = 3 * colIndexOfSquare;

        for(int i=0; i<9; i++){
            if(board[row][i]==num) return false;
            if(board[i][col]==num) return false;

            int xRow = rowIndexOfFirstElement + i/3;
            int yCol = colIndexOfFirstElement + i%3;

            if(board[xRow][yCol]==num) return false;
        }
        return true;
    }

    public void solveSudoku(char[][] board) {
        solve(board,0,0);
    }
}
0
Subscribe to my newsletter

Read articles from Chetan Datta directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Chetan Datta
Chetan Datta

I'm someone deeply engrossed in the world of software developement, and I find joy in sharing my thoughts and insights on various topics. You can explore my exclusive content here, where I meticulously document all things tech-related that spark my curiosity. Stay connected for my latest discoveries and observations.