Start learning free

LESSON 403 OF 671 · BACKTRACKING

Sudoku Solver in JavaScript (Time Complexity: O(9^(n*n)))

Practice O(nn2) Read the full explanation

You get an unfinished Sudoku board with 9 rows and 9 columns. Each cell is a character. It is a digit from '1' to '9', or '.' for an empty cell.

Return the board with every empty cell filled in.

The finished board must follow three rules:

  1. Each row holds the digits 1 to 9 once.
  2. Each column holds the digits 1 to 9 once.
  3. Each 3 x 3 block holds the digits 1 to 9 once. The thick lines in the picture below mark the nine blocks.

The digits already on the board stay where they are.

 

Example 1:

382 132 745 567 657134 784 326 685 572

Input: board = [
  [".","3","8",".",".","2",".",".","."],
  [".","1",".","3",".",".","2",".","."],
  [".",".",".",".","7","4","5",".","."],
  [".",".",".",".","5","6",".","7","."],
  ["6",".","5","7",".","1","3",".","4"],
  [".","7",".","8","4",".",".",".","."],
  [".",".","3","2","6",".",".",".","."],
  [".",".","6",".",".","8",".","5","."],
  [".",".",".","5",".",".","7","2","."]
]
Output: [
  ["5","3","8","6","9","2","4","1","7"],
  ["4","1","7","3","8","5","2","6","9"],
  ["2","6","9","1","7","4","5","3","8"],
  ["3","8","4","9","5","6","1","7","2"],
  ["6","9","5","7","2","1","3","8","4"],
  ["1","7","2","8","4","3","6","9","5"],
  ["9","5","3","2","6","7","8","4","1"],
  ["7","2","6","4","1","8","9","5","3"],
  ["8","4","1","5","3","9","7","2","6"]
]
Explanation: The puzzle is drawn above.
It has exactly one solution, drawn below.
The digits you add are in blue.


  
  
  
  
    382
    132
    745
    567
    657134
    784
    326
    685
    572
  
  
    569417
    478569
    269138
    384912
    928
    123695
    957841
    724193
    841396
  

 

Constraints:

  • The board is always 9 rows of 9 cells.
  • A cell is a digit from '1' to '9' or '.' (empty).
  • Every puzzle you get has exactly one solution.

STEP 1 OF 29
    Ctrl + Enter to check

    JAVASCRIPT · BACKTRACKING

    Sudoku in JavaScript, explained

    Understanding the Problem

    The core challenge of solving a Sudoku puzzle lies in ensuring that each number from 1 to 9 appears exactly once in each row, column, and 3x3 sub-box. This problem is significant in various fields such as constraint satisfaction problems, artificial intelligence, and recreational mathematics. A common pitfall is not considering all constraints simultaneously, leading to invalid solutions.

    Approach

    To solve the Sudoku puzzle, we can use a backtracking algorithm. The idea is to try placing each number from 1 to 9 in each empty cell and recursively attempt to solve the puzzle. If a number placement leads to a conflict, we backtrack and try the next number.

    Naive Solution

    A naive solution would involve trying every possible combination of numbers in the empty cells, which is computationally infeasible due to the vast number of possibilities.

    Optimized Solution

    The optimized solution uses backtracking with constraint propagation. This approach significantly reduces the number of possibilities by eliminating invalid choices early.

    Algorithm

    Here is a step-by-step breakdown of the backtracking algorithm:

    1. Find an empty cell.
    2. Try placing each number from 1 to 9 in the empty cell.
    3. Check if the number placement is valid (i.e., it doesn't violate Sudoku rules).
    4. If valid, recursively attempt to solve the rest of the board.
    5. If the board is solved, return true.
    6. If not, backtrack by removing the number and trying the next one.
    7. If no number is valid, return false.

    Code Implementation

    /**
     * Solves the Sudoku puzzle.
     * @param {character[][]} board - The 9x9 Sudoku board.
     * @return {void} Do not return anything, modify board in-place instead.
     */
    function solveSudoku(board) {
        // Helper function to check if placing num at board[row][col] is valid
        function isValid(board, row, col, num) {
            for (let i = 0; i < 9; i++) {
                // Check row, column, and 3x3 sub-box
                if (board[row][i] === num || board[i][col] === num || 
                    board[Math.floor(row / 3) * 3 + Math.floor(i / 3)][Math.floor(col / 3) * 3 + i % 3] === num) {
                    return false;
                }
            }
            return true;
        }
    
        // Helper function to solve the board using backtracking
        function solve(board) {
            for (let row = 0; row < 9; row++) {
                for (let col = 0; col < 9; col++) {
                    if (board[row][col] === '.') {
                        for (let num = '1'; num <= '9'; num++) {
                            if (isValid(board, row, col, num)) {
                                board[row][col] = num;
                                if (solve(board)) {
                                    return true;
                                }
                                board[row][col] = '.'; // Backtrack
                            }
                        }
                        return false; // No valid number found, trigger backtracking
                    }
                }
            }
            return true; // Solved
        }
    
        solve(board);
    }
    

    Complexity Analysis

    The time complexity of the backtracking algorithm is O(9^(n*n)), where n is the size of the board (9 in this case). The space complexity is O(n*n) due to the recursion stack.

    Edge Cases

    Potential edge cases include:

    • A nearly completed board with only one empty cell.
    • A board with multiple empty cells in a single row, column, or sub-box.

    Each algorithm handles these cases by ensuring all constraints are checked before placing a number.

    Testing

    To test the solution comprehensively, use a variety of test cases:

    • Simple cases with only a few empty cells.
    • Complex cases with many empty cells.
    • Edge cases as mentioned above.

    Testing frameworks like Jest or Mocha can be used for automated testing.

    Thinking and Problem-Solving Tips

    When approaching such problems:

    • Break down the problem into smaller, manageable parts.
    • Use diagrams or pseudo-code to visualize the solution.
    • Practice similar problems to improve problem-solving skills.

    Conclusion

    Solving Sudoku puzzles programmatically is an excellent exercise in understanding backtracking and constraint satisfaction problems. By practicing and exploring further, one can develop strong problem-solving skills.

    Additional Resources

    For further reading and practice:

    Keep going with JavaScript650+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free