Fork me on GitHub

Sudoku Solver

Sudoku Solver

Description

https://leetcode.com/problems/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 the digits 1-9 must occur exactly once in each of the 9 3x3 sub-boxes of the grid.

Empty cells are indicated by the character '.'.

Solution

This is a brutal-force implementation of Sudoku algorithm, The solution ism quite straightforward, we choose each empty cell, try values from 1 to 9, once validated, then we recursively call the solver function, until there is no other empty cell.

Code

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
class Solution(object):
def solveSudoku(self, board):
"""
:type board: List[List[str]]
:rtype: void Do not return anything, modify board in-place instead.
"""
self.numbers = ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
self.solveSu(board)

def solveSu(self, board):
for i in range(9):
for j in range(9):
if board[i][j] == '.':
for k in self.numbers:
if self.validateSudoku(board, k, i, j):
board[i][j] = k
if self.solveSu(board):
return True
else:
board[i][j] = '.'
return False

return True

def validateSudoku(self, board, k, i, j):
for index in range(9):
if board[i][index] == k:
return False

for index in range(9):
if board[index][j] == k:
return False

start_row = int(i/3)*3
start_col = int(j/3)*3
for index_row in range(start_row, start_row+3):
for index_col in range(start_col, start_col+3):
if board[index_row][index_col] == k:
return False

return True

Improvement

A little trick to make the backtracing faster is accelerate the validation process, by using hash table in each row, each column, each block.

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
class Solution(object):
def solveSudoku(self, board):
"""
:type board: List[List[str]]
:rtype: void Do not return anything, modify board in-place instead.
"""
self.numbers = ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
self.row_hash = [{} for j in range(9)]
self.col_hash = [{} for j in range(9)]
self.block_hash = [{} for j in range(9)]

for i in range(9):
for j in range(9):
if board[i][j] != '.':
value = board[i][j]
self.row_hash[i][value] = True
self.col_hash[j][value] = True
self.block_hash[int(i/3)*3+(int(j/3))][value] = True
self.solveSu(board)


def solveSu(self, board):
for i in range(9):
for j in range(9):
if board[i][j] == '.':
for k in self.numbers:
if self.validateSudoku(board, k, i, j):
board[i][j] = k
self.row_hash[i][k] = True
self.col_hash[j][k] = True
self.block_hash[int(i/3)*3+(int(j/3))][k] = True
if self.solveSu(board):
return True
else:
board[i][j] = '.'
self.row_hash[i][k] = False
self.col_hash[j][k] = False
self.block_hash[int(i/3)*3+(int(j/3))][k] = False
return False

return True

def validateSudoku(self, board, k, i, j):
if self.row_hash[i].get(k) or self.col_hash[j].get(k) or self.block_hash[int(i/3)*3+(int(j/3))].get(k):
return False


return True

Experiment