Skip to content

37. Sudoku Solver

Description

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.

Solutions

Solution 1: Backtracking

We use arrays \(\textit{row}\), \(\textit{col}\), and \(\textit{box}\) to record whether each number has appeared in each row, each column, and each 3x3 sub-box, respectively. If the number \(i\) has appeared in row \(r\), column \(c\), or the \(b\)-th 3x3 sub-box, then \(\text{row[r][i]}\), \(\text{col[c][i]}\), and \(\text{box[b][i]}\) are all set to \(true\).

We iterate over every empty cell in the \(\textit{board}\) and enumerate the possible numbers \(v\) that can be filled in. If \(v\) has not appeared in the current row, column, or 3x3 sub-box, we can try filling in \(v\) and continue searching for the next empty cell. If we reach the end and all cells are filled, it means we have found a valid solution.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Solution:
    def solveSudoku(self, board: List[List[str]]) -> None:
        def dfs(k):
            nonlocal ok
            if k == len(t):
                ok = True
                return
            i, j = t[k]
            for v in range(9):
                if row[i][v] == col[j][v] == block[i // 3][j // 3][v] == False:
                    row[i][v] = col[j][v] = block[i // 3][j // 3][v] = True
                    board[i][j] = str(v + 1)
                    dfs(k + 1)
                    row[i][v] = col[j][v] = block[i // 3][j // 3][v] = False
                if ok:
                    return

        row = [[False] * 9 for _ in range(9)]
        col = [[False] * 9 for _ in range(9)]
        block = [[[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] = block[i // 3][j // 3][v] = True
        dfs(0)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class Solution {
    private boolean ok;
    private char[][] board;
    private List<Integer> t = new ArrayList<>();
    private boolean[][] row = new boolean[9][9];
    private boolean[][] col = new boolean[9][9];
    private boolean[][][] block = new boolean[3][3][9];

    public void solveSudoku(char[][] board) {
        this.board = board;
        for (int i = 0; i < 9; ++i) {
            for (int j = 0; j < 9; ++j) {
                if (board[i][j] == '.') {
                    t.add(i * 9 + j);
                } else {
                    int v = board[i][j] - '1';
                    row[i][v] = col[j][v] = block[i / 3][j / 3][v] = true;
                }
            }
        }
        dfs(0);
    }

    private void dfs(int k) {
        if (k == t.size()) {
            ok = true;
            return;
        }
        int i = t.get(k) / 9, j = t.get(k) % 9;
        for (int v = 0; v < 9; ++v) {
            if (!row[i][v] && !col[j][v] && !block[i / 3][j / 3][v]) {
                row[i][v] = col[j][v] = block[i / 3][j / 3][v] = true;
                board[i][j] = (char) (v + '1');
                dfs(k + 1);
                row[i][v] = col[j][v] = block[i / 3][j / 3][v] = false;
            }
            if (ok) {
                return;
            }
        }
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class Solution {
public:
    void solveSudoku(vector<vector<char>>& board) {
        bool row[9][9] = {false};
        bool col[9][9] = {false};
        bool block[3][3][9] = {false};
        bool ok = false;
        vector<pair<int, int>> t;
        for (int i = 0; i < 9; ++i) {
            for (int j = 0; j < 9; ++j) {
                if (board[i][j] == '.') {
                    t.push_back({i, j});
                } else {
                    int v = board[i][j] - '1';
                    row[i][v] = col[j][v] = block[i / 3][j / 3][v] = true;
                }
            }
        }
        auto dfs = [&](this auto&& dfs, int k) -> void {
            if (k == t.size()) {
                ok = true;
                return;
            }
            int i = t[k].first, j = t[k].second;
            for (int v = 0; v < 9; ++v) {
                if (!row[i][v] && !col[j][v] && !block[i / 3][j / 3][v]) {
                    row[i][v] = col[j][v] = block[i / 3][j / 3][v] = true;
                    board[i][j] = v + '1';
                    dfs(k + 1);
                    row[i][v] = col[j][v] = block[i / 3][j / 3][v] = false;
                }
                if (ok) {
                    return;
                }
            }
        };
        dfs(0);
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
func solveSudoku(board [][]byte) {
    var row, col [9][9]bool
    var block [3][3][9]bool
    var t [][2]int
    ok := false
    for i := 0; i < 9; i++ {
        for j := 0; j < 9; j++ {
            if board[i][j] == '.' {
                t = append(t, [2]int{i, j})
            } else {
                v := int(board[i][j] - '1')
                row[i][v], col[j][v], block[i/3][j/3][v] = true, true, true
            }
        }
    }
    var dfs func(int)
    dfs = func(k int) {
        if k == len(t) {
            ok = true
            return
        }
        i, j := t[k][0], t[k][1]
        for v := 0; v < 9; v++ {
            if !row[i][v] && !col[j][v] && !block[i/3][j/3][v] {
                row[i][v], col[j][v], block[i/3][j/3][v] = true, true, true
                board[i][j] = byte(v + '1')
                dfs(k + 1)
                row[i][v], col[j][v], block[i/3][j/3][v] = false, false, false
            }
            if ok {
                return
            }
        }
    }
    dfs(0)
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class Solution {
    public void SolveSudoku(char[][] board) {
        bool[,] row = new bool[9, 9];
        bool[,] col = new bool[9, 9];
        bool[,,] block = new bool[3, 3, 9];
        bool ok = false;
        var t = new List<(int, int)>();

        for (int i = 0; i < 9; ++i) {
            for (int j = 0; j < 9; ++j) {
                if (board[i][j] == '.') {
                    t.Add((i, j));
                } else {
                    int v = board[i][j] - '1';
                    row[i, v] = col[j, v] = block[i / 3, j / 3, v] = true;
                }
            }
        }

        void Dfs(int k) {
            if (k == t.Count) {
                ok = true;
                return;
            }
            var (i, j) = t[k];
            for (int v = 0; v < 9; ++v) {
                if (!row[i, v] && !col[j, v] && !block[i / 3, j / 3, v]) {
                    row[i, v] = col[j, v] = block[i / 3, j / 3, v] = true;
                    board[i][j] = (char)(v + '1');
                    Dfs(k + 1);
                    if (ok) return;
                    row[i, v] = col[j, v] = block[i / 3, j / 3, v] = false;
                }
            }
        }

        Dfs(0);
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class Solution {
    /**
     * @param String[][] $board
     * @return NULL
     */
    function solveSudoku(&$board) {
        $row = array_fill(0, 9, array_fill(0, 9, false));
        $col = array_fill(0, 9, array_fill(0, 9, false));
        $block = array_fill(0, 3, array_fill(0, 3, array_fill(0, 9, false)));
        $ok = false;
        $t = [];

        for ($i = 0; $i < 9; ++$i) {
            for ($j = 0; $j < 9; ++$j) {
                if ($board[$i][$j] === '.') {
                    $t[] = [$i, $j];
                } else {
                    $v = ord($board[$i][$j]) - ord('1');
                    $row[$i][$v] = true;
                    $col[$j][$v] = true;
                    $block[intval($i / 3)][intval($j / 3)][$v] = true;
                }
            }
        }

        $dfs = function ($k) use (&$dfs, &$board, &$row, &$col, &$block, &$ok, &$t) {
            if ($k === count($t)) {
                $ok = true;
                return;
            }
            [$i, $j] = $t[$k];
            for ($v = 0; $v < 9; ++$v) {
                if (!$row[$i][$v] && !$col[$j][$v] && !$block[intval($i / 3)][intval($j / 3)][$v]) {
                    $row[$i][$v] = $col[$j][$v] = $block[intval($i / 3)][intval($j / 3)][$v] = true;
                    $board[$i][$j] = chr($v + ord('1'));
                    $dfs($k + 1);
                    if ($ok) {
                        return;
                    }
                    $row[$i][$v] = $col[$j][$v] = $block[intval($i / 3)][intval($j / 3)][
                        $v
                    ] = false;
                }
            }
        };

        $dfs(0);
    }
}

Comments