Algorithm to Solve Sudoku Using Python

A Sudoku is a type of puzzle with number placement. The objective of this game is to complete a square grid of n size with numbers from 0 - 9 or 1 - n. The number in the Sudoku must be placed in each column, each row, and each sub-grid consists of the number from 1 - 'n'. Most sudoku puzzles contain a 9 x 9 grid, and the grids are not fully or partially filled with hints to confirm the solution can be reached.

This type of problem is mostly asked in technical round of the big tech companies such as Amazon, Google, Microsoft.

The company gives the problem description as follows. You have a sudoku puzzle in the 2D matrix form, and you must complete the cells without breaking any rules. The rules for the sudoku puzzle are given below.

  1. Each digit from 1-9 must be present in each row.
  2. Each digit from 1-9 must be present in each column.
  3. Each digit from 1-9 must be present in each of the 3x3 subgrids.

A board is given that contains digits 1-9 and the character '.'. There should be a unique solution to the puzzle and the size of given board is always 9x9. The character '.' represents an empty cell.

The example shows the given sudoku puzzle.

Algorithm to Solve Sudoku Using Python

The above image shows a sudoku puzzle of 9x9. The puzzle contains 3x3 sub-grids with some digits that are partially filled. The aim of this game is to fill the box with values from 1-9, and each row, each column and each grid should have unique values.

The solution to the above puzzle is:

Algorithm to Solve Sudoku Using Python

The red numbers show the solution to the puzzle.

Let's see how, in Programming, the input is given as:

Input: Puzzle

In the above input, there is a 9x9 2D matrix that is sparse, which means it contains more zeros. The goal is to replace the 0 with the digit from 1-9, and each row and column should contain unique digits.

Output:

3 1 6 5 7 8 4 9 2
5 2 9 1 3 4 7 6 8
4 8 7 6 2 9 5 3 1
2 6 3 4 1 5 9 8 7
9 7 4 8 6 3 1 2 5
8 5 1 7 9 2 6 4 3
1 3 8 9 4 7 2 5 6
6 9 2 3 5 1 8 7 4
7 4 5 2 8 6 3 1 9

In the output, we can see that 0 is replaced with the digits from 1-9, and each row, column, and 3x3 grid of the output contains unique values.

There are many approaches to solving the sudoku puzzle. The approaches are:

Naïve Approach: In this approach, all the possible solutions are generated for numbers from 1 to 9 to complete the empty cells. Every configuration is checked one by one until the correct puzzle is formed. For each position that is unassigned, fill the position with a digit from 1 - 9. After the unassigned position is filled, check if the matrix is saved or not. If the puzzle matrix is safe, it recurs for another case.

Here are some steps to solve the problem using Naïve Approach.

  1. First, a function is created to check if the matrix that is given is a valid sudoku or not. A hashmap is made for each row, column and box. If a number has an occurrence greater than 1 in the hashmap, return false; else, return true.
  2. A recursive function is created that takes a grid and the current row and column index.
  3. Some base cases have been checked.
    1. If the index present at the end of the matrix means i = N-1 and j = N, then the condition check for the grid is safe or not; if the grid is safe, then the grid is printed, and the true is returned by the function. Else, the value is returned as false.
    2. The second base case is when the column value is N, which means the value of j = N, then the index value is moved to the next row, i.e., the value of i is updated to i++ and j = 0.
  4. If the value is not assigned to the current index, then the index is filled with the value 1 to 9, and all the 9 cases are recured with the index of the next element, that is, i, j + 1. If the value is returned true by the recursive call then the loop is break and the true value is returned.
  5. If the current index is assigned then the recursive function is called with the index of the next element that is I, j + 1.

The implementation of the above algorithm is:

Code:

Output:

3 1 6 5 7 8 4 9 2 
5 2 9 1 3 4 7 6 8 
4 8 7 6 2 9 5 3 1 
2 6 3 4 1 5 9 8 7 
9 7 4 8 6 3 1 2 5 
8 5 1 7 9 2 6 4 3 
1 3 8 9 4 7 2 5 6 
6 9 2 3 5 1 8 7 4 
7 4 5 2 8 6 3 1 9 

Explanation:

In the above code, the size of the puzzle is defined as 9, which is a 3x3, 2D matrix. A function is defined to be used to print the 2D puzzle, and another function is made to check whether the index and cell are safe or not. The function accepts the parameters of grid, row, column, and number. In the function, for all the values from 1 to 9, the condition is checked, and if the same number is found in a similar row, then it is returned false. Otherwise, if the same number is found in the column, then also return false. If these same numbers are found in the 3x3 matrix, they also return false. Another function is the solve sudoku function, which accepts the parameters of the grid, row, and column. In the function, first, it is checked that if we have reached the 8th row and 9th column, and if it is true, then return True to avoid further Backtracking, and it is the based condition of the function. Next, the condition is checked that if column values become 9, then move to the next row, and the column starts from 0. If the current position of the grid is already filled, then move to the next column. Then check the safe place.

The numbers 1 to 9 in the given row and column move to the next column. Assign the number in the current row and column of the grid and assume that the number that is assigned in the position is correct. After assigning the number, check for the next possibility in the next column. Remove the assigned number since the assumption that was made was wrong, and go for the next assumption with a different number value.

Time Complexity: The time complexity of the above approach is O(9(N*N)); for each unassigned index, there are 9 possible options. So, the time complexity is O(9(N*N)).

Space Complexity: The space complexity of the above approach is O(N*N). A 2D matrix is needed to store the output.

Algorithm to Solve Sudoku using Backtracking:

Sudoku can be solved by assigning the numbers one by one to the cells that are empty. First, check whether the given cell is safe or not for assigning the number, then assign the number. A condition is checked to see whether the same number is present in the current row, current column, and current 3x3 subgrid or not. If it is saved, then the number is assigned, and recursively check whether the number that is assigned leads to a solution or not. If there is no solution after assigning the number, then the next number is tried for the current empty cell. If there is a number 1 to 9, give a solution for the puzzle, then return false and print that no solution exists.

Here are the steps to solve the sudoku puzzle problem with the help of Backtracking.

  1. A function is created that checks whether the given grid is safe or not after the current index value is assigned to the number. A hashmap is maintained for a row, column and boxes. If the occurrence of any number is greater than 1 in the hashMap the false is returned else true is returned. Hashmap can be avoided with the help of loops.
  2. A recursive function that takes a grid is created.
  3. A statement checks if there is any unassigned location or not.
    1. If the location is present, then the number assigned is from 1 to 9.
    2. A statement checks the number assigned to the current index to make the grid safe or not.
    3. If the current index is safe, then call the function recursively for all safe cases from 0 to 9.
    4. If true is returned by any recursive call, end the loop and return true. If no true returned by any recursive call then return false.
  4. If there is no unassigned location left, then return true.

Code:

Output:

3 1 6 5 7 8 4 9 2 
5 2 9 1 3 4 7 6 8 
4 8 7 6 2 9 5 3 1 
2 6 3 4 1 5 9 8 7 
9 7 4 8 6 3 1 2 5 
8 5 1 7 9 2 6 4 3 
1 3 8 9 4 7 2 5 6 
6 9 2 3 5 1 8 7 4 
7 4 5 2 8 6 3 1 9

Explanation:

In the above code, Backtracking is used to solve the sudoku puzzle. In the code, the display function is used to print the puzzle when it is complete. A function that finds the entry in the grid that is still not used. The grid is searched to find an entry that has not yet been assigned. If the entry is found, the reference row, col, will be set for the location that is unassigned, and true is returned. If there are no unassigned entries left, false is returned by the function. In the code, l is the list variable that has been passed from the solve sudoku function to keep the record for the incrementation of rows and columns. A Boolean value is returned, which shows whether any assigned entry in the specified row matches the given number or not. A state is checked to see whether the number assigned is legal or not to the given row, col, and grid. A Boolean value is returned, which shows whether it will be legal to assign num to the given row, col location. The last function, the solveSudoku function, completes the whole grid that takes the input of a partially filled-in grid and tries to assign values to all unassigned locations in such a way as to meet the requirements for a sudoku solution.

  • Time complexity: The time complexity of the above algorithm is O(9(N*N)), and each unassigned index has 9 possibilities, so the time complexity is O(9(N*N)). The time complexity remains the same as the naïve approach, but the difference is that there will be some early pruning, so the time taken will be less than the naïve approach.
  • Space Complexity: The space complexity of the algorithm is O(N*N) because a matrix needs to be maintained for output.

Sudoku using Bit Masks:

The bit mask method is another optimized solution for solving the sudoku problem. In this method for every row, column and 3x3 grid, a bitmask is created and for each element in the grid, the position value is set to 1 for O(1) check.

Algorithm for the Bit Masks:

  1. Three arrays are created of size N (one for row, one for column and one for 3x3 boxes).
  2. The index values for the boxes are set to 0 to 8.
  3. The initial values are mapped to the first grid.
  4. Each time an element is added or removed from the grid set the bit to 1 or 0 for the corresponding bitmasks.

Code:

Output:

3 1 6 5 7 8 4 9 2 
5 2 9 1 3 4 7 6 8 
4 8 7 6 2 9 5 3 1 
2 6 3 4 1 5 9 8 7 
9 7 4 8 6 3 1 2 5 
8 5 1 7 9 2 6 4 3 
1 3 8 9 4 7 2 5 6 
6 9 2 3 5 1 8 7 4 
7 4 5 2 8 6 3 1 9 

Explanation:

In the above code for the sudoku problem, the print_grid function is used to print the full sudoku grid, a function that checks the safe condition of the row, column and the 3x3 grid. Another function that is used to solve the sudoku puzzle is That if the index reaches the 8th row and 9th column, true is returned to avoid further Backtracking. A condition is checked to determine if the column value becomes 9 or not. If the column becomes 9, the index is moved to the next row, and the column starts from 0. If the current position of the grid has values greater than 0, then iterate for the next column. If the index position is safe, place the number (1-9) in the given row and move to the next column. Assing the number in the current row or column position of the grid and assume that our assigned number in the position is correct. Check for the next possibility in the next column.

  • Time Complexity: The complexity of the above algorithm is O(9(N*N)) for each index that is not assigned having 9 possibilities. So, the time complexity is O(9(N*N)).
  • Space Complexity: The space complexity of the algorithm is O(N*N) because an output array is needed to store the output, and 3 extra arrays having size n are also needed for the bitmasks.

Solving Sudoku Using Cross-Hatching with Backtracking:

This is an optimized method for the bit mask method. It is 5 times faster than the bit mask method. In the bit-wise method, Sudoku is filled out by first finding the element that is almost filled. In this method, the row and column are identified where the element should be placed.

Here's the algorithm to solve the sudoku puzzle:

  1. A graph is made with the elements that are left and mapped to row, and column coordinates where they can be placed in the original matrix.
  2. An element is picked from the graph and sorted by fewer remaining elements to be filled.
  3. Fill the elements recursively with the help of a graph into the matrix. Backtrack once an unsafe position is found.

Code:

Output:

[3, 1, 6, 5, 7, 8, 4, 9, 2]
[5, 2, 9, 1, 3, 4, 7, 6, 8]
[4, 8, 7, 6, 2, 9, 5, 3, 1]
[2, 6, 3, 4, 1, 5, 9, 8, 7]
[9, 7, 4, 8, 6, 3, 1, 2, 5]
[8, 5, 1, 7, 9, 2, 6, 4, 3]
[1, 3, 8, 9, 4, 7, 2, 5, 6]
[6, 9, 2, 3, 5, 1, 8, 7, 4]
[7, 4, 5, 2, 8, 6, 3, 1, 9]

Conclusion:

Sudoku puzzle problem is a famous problem that is asked in many MNCs and there are many methods to solve the problem. Backtracking is the best approach to solve the problem.