leetcode: 回溯 37. Sudoku Solver

题目:

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 '.'.


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)
发布了45 篇原创文章 · 获赞 1 · 访问量 3379

猜你喜欢

转载自blog.csdn.net/qq_22498427/article/details/104465464