题目:
Write a program to solve a Sudoku puzzle by filling the empty cells.
A sudoku solution must satisfy all of the following rules:
- Each of the digits
1-9
must occur exactly once in each row. - Each of the digits
1-9
must occur exactly once in each column. - Each of the the digits
1-9
must occur exactly once in each of the 93x3
sub-boxes of the grid.
Empty cells are indicated by the character '.'
.
A sudoku puzzle...
...and its solution numbers marked in red.
Note:
- The given board contain only digits
1-9
and the character'.'
. - You may assume that the given Sudoku puzzle will have a single unique solution.
- The given board size is always
9x9
.
思路:
维护四个列表,行,列,cube还可以填入的数字;剩余空格位置
同时维护一个 list,list中一共9项内容,表示可填入数字个数
1、首先将可填入数字个数为 1 的空格填入数字,并更新 其所在行、列、3*3单元格内剩余空格的可填入数字
2、所有都填完后,若还有空格,对一个空格选择一个数字填,看能否行的通,不行换个数字。
答案:
import copy
import collections
class Solution:
def update(self,num_insert,check_insert,insert_len,empty_d1,empty_d2,empty_block,ij,num):
# 更新cube的可填入数字
i = int(ij)//10
j = int(ij)%10
empty_d2[j].remove(i)
empty_d1[i].remove(j)
empty_block[i//3][j//3].remove(ij)
for d1 in empty_d2[j]:
if num in num_insert[str(d1)+str(j)]:
num_insert[str(d1)+str(j)].remove(num)
insert_len[len(num_insert[str(d1)+str(j)])].append(str(d1)+str(j))
insert_len[len(num_insert[str(d1)+str(j)])+1].remove(str(d1)+str(j))
for d2 in empty_d1[i]:
if num in num_insert[str(i)+str(d2)]:
num_insert[str(i)+str(d2)].remove(num)
insert_len[len(num_insert[str(i)+str(d2)])].append(str(i)+str(d2))
insert_len[len(num_insert[str(i)+str(d2)])+1].remove(str(i)+str(d2))
for ij in empty_block[i//3][j//3]:
if num in num_insert[ij]:
num_insert[ij].remove(num)
insert_len[len(num_insert[ij])].append(ij)
insert_len[len(num_insert[ij])+1].remove(ij)
if len(insert_len[0])>0:
return False
else:
return True
def insertNum(self,board,num_insert,check_insert,insert_len,empty_d1,empty_d2,empty_block):
#填数字
while len(insert_len[1])>0:
ij = insert_len[1].pop()
i = int(ij)//10
j = int(ij)%10
num = num_insert[ij].pop()
board[i][j] = num
if not self.update(num_insert,check_insert,insert_len,empty_d1,empty_d2,empty_block,ij,num):
return False
if sum([len(insert_len[i]) for i in range(0,10)])>0:
for i in range(2,10):
while len(insert_len[i])>0:
ij = insert_len[i].pop()
i = int(ij)//10
j = int(ij)%10
for num in num_insert[ij]:
board[i][j] = num
num_insert_new,check_insert_new,insert_len_new,empty_d1_new,empty_d2_new,empty_block_new = copy.deepcopy(num_insert),copy.deepcopy(check_insert),copy.deepcopy(insert_len),copy.deepcopy(empty_d1),copy.deepcopy(empty_d2),copy.deepcopy(empty_block)
if self.update(num_insert_new,check_insert_new,insert_len_new,empty_d1_new,empty_d2_new,empty_block_new,ij,num):
if self.insertNum(board,num_insert_new,check_insert_new,insert_len_new,empty_d1_new,empty_d2_new,empty_block_new):
return True
return False
else:
return True
def solveSudoku(self, board) -> None:
# 首先根据输入的board内容,用几个表来存放,每行有哪些空格,每列有哪些空格,每个3*3单元由哪些空格,每个空格可以填入什么数字,
num_insert = collections.defaultdict(list)
check_insert = collections.defaultdict(lambda:[str(i) for i in range(1,10)])
insert_len = [[],[],[],[],[],[],[],[],[],[]]
empty_d1 = [[],[],[],[],[],[],[],[],[]]
empty_d2 = [[],[],[],[],[],[],[],[],[]]
empty_block = [[[],[],[]],[[],[],[]],[[],[],[]]]
for i in range(9):
for j in range(9):
if board[i][j] != ".":
num_insert[str(i)+str(j)] = []
check_insert["d1"+str(i)].remove(board[i][j])
check_insert["d2"+str(j)].remove(board[i][j])
check_insert["block"+str(i//3)+str(j//3)].remove(board[i][j])
else:
empty_d1[i].append(j)
empty_d2[j].append(i)
empty_block[i//3][j//3].append(str(i)+str(j))
insert_len[9].append(str(i)+str(j))
while len(insert_len[9])>0:
ij = insert_len[9].pop()
i = int(ij)//10
j = int(ij)%10
for num in check_insert["d1"+str(i)]:
if (num in check_insert["d2"+str(j)]) and (num in check_insert["block"+str(i//3)+str(j//3)]):
num_insert[ij].append(num)
insert_len[len(num_insert[ij])].append(ij)
# 根据上面的几个表,填数字
self.insertNum(board,num_insert,check_insert,insert_len,empty_d1,empty_d2,empty_block)