Start learning free

LESSON 399 OF 667 · BACKTRACKING

Sudoku Solver in C++ (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 char. 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

    C++ · BACKTRACKING

    Sudoku in C++, explained

    Understanding the Problem

    The core challenge of solving a Sudoku puzzle is to fill the empty cells such that each digit 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 to overlook the constraints, leading to invalid solutions.

    Approach

    To solve the Sudoku puzzle, we can use a backtracking algorithm. The idea is to try filling the empty cells one by one and backtrack if we encounter an invalid state. Here's a step-by-step approach:

    1. Find an empty cell.
    2. Try placing digits from 1 to 9 in the empty cell.
    3. Check if the digit placement is valid (i.e., it doesn't violate Sudoku rules).
    4. If valid, recursively attempt to fill the next empty cell.
    5. If invalid or if we can't fill the next cell, backtrack and try the next digit.
    6. Repeat until the board is completely filled.

    Let's break down the algorithm and its implementation in C++.

    Algorithm

    Here's a detailed breakdown of the backtracking algorithm:

    1. Find an empty cell: Iterate through the board to find a cell with the '.' character.
    2. Try placing digits: For each digit from 1 to 9, check if placing the digit in the current cell is valid.
    3. Check validity: Ensure the digit doesn't already exist in the current row, column, or 3x3 sub-box.
    4. Recursive call: If the digit placement is valid, make a recursive call to attempt to fill the next empty cell.
    5. Backtrack: If the recursive call returns false, reset the cell and try the next digit.
    6. Completion: If all cells are filled, the board is solved.

    Code Implementation

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    // Function to check if placing a number is valid
    bool isValid(vector<vector<char>>& board, int row, int col, char num) {
        for (int i = 0; i < 9; i++) {
            // Check row
            if (board[row][i] == num) return false;
            // Check column
            if (board[i][col] == num) return false;
            // Check 3x3 sub-box
            if (board[row / 3 * 3 + i / 3][col / 3 * 3 + i % 3] == num) return false;
        }
        return true;
    }
    
    // Backtracking function to solve the Sudoku
    bool solveSudoku(vector<vector<char>>& board) {
        for (int row = 0; row < 9; row++) {
            for (int col = 0; col < 9; col++) {
                if (board[row][col] == '.') {
                    for (char num = '1'; num <= '9'; num++) {
                        if (isValid(board, row, col, num)) {
                            board[row][col] = num;
                            if (solveSudoku(board)) return true;
                            board[row][col] = '.'; // Backtrack
                        }
                    }
                    return false; // No valid number found
                }
            }
        }
        return true; // Solved
    }
    
    int main() {
        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'}
        };
    
        if (solveSudoku(board)) {
            for (const auto& row : board) {
                for (const auto& cell : row) {
                    cout << cell << ' ';
                }
                cout << endl;
            }
        } else {
            cout << "No solution exists" << endl;
        }
    
        return 0;
    }
    

    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). This is because, in the worst case, we might have to try all 9 digits for each cell. The space complexity is O(n*n) due to the recursion stack and the board itself.

    Edge Cases

    Potential edge cases include:

    • Boards that are already solved.
    • Boards with only one empty cell.
    • Boards with multiple empty cells but only one valid solution.

    Each algorithm should handle these cases effectively by ensuring the constraints are always met.

    Testing

    To test the solution comprehensively, consider the following test cases:

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

    Using a testing framework like Google Test can help automate and validate these test cases.

    Thinking and Problem-Solving Tips

    When approaching such problems, consider the following tips:

    • Break down the problem into smaller, manageable parts.
    • Use a systematic approach to explore all possibilities.
    • Practice solving similar problems to improve your skills.

    Conclusion

    Solving a Sudoku puzzle using backtracking is a classic example of constraint satisfaction problems. Understanding and implementing this algorithm helps improve problem-solving skills and provides a foundation for tackling more complex problems.

    Additional Resources

    For further reading and practice, consider the following resources:

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