leetcode 每日一题 37. 解数独

回溯法

思路:

①首先建立三个数组,分别记录每行每列和每个3x3宫内出现过的数字,从第0行第0列开始进行②

②如果遇到的字符不是' . ',则进行填入下一个值操作。如果遇到字符是' . '则填数字,可以填入数字范围为1-9,每填入一个数字需要进行判断,如果这个数字在对应所在行、列、和3x3宫内出现过,则此数字不能填入。如果没有出现过,则填入数字,同时更新三个数组和board中相应位置的值。接着填入下一个值,如果在进行填入下一个值这步操作后,问题没有的到解决,意味着填入的数字无法得到最终解,则还原board填入的值,同时更新三个数组中相应位置值,继续尝试下一个可能的数字。

③填入下一个数所要做的操作是,如果当前数字已经是最后一个数字,则问题解决,得到答案,如果不是最后一个数字,根据判断列号得到下一个要填入数字的下标,回溯到②

如下图:

代码:

from collections import defaultdict
class Solution:
    def solveSudoku(self, board):
        def could_place(d, row, col):
            return not (d in rows[row] or d in columns[col] or \
                    d in boxes[box_index(row, col)])
        def place_number(d, row, col):
            rows[row][d] += 1
            columns[col][d] += 1
            boxes[box_index(row, col)][d] += 1
            board[row][col] = str(d)   
        def remove_number(d, row, col):
            del rows[row][d]
            del columns[col][d]
            del boxes[box_index(row, col)][d]
            board[row][col] = '.'     
        def place_next_numbers(row, col):
            if col == N - 1 and row == N - 1:
                nonlocal sudoku_solved
                sudoku_solved = True   
            else:
                if col == N - 1:
                    backtrack(row + 1, 0)
                else:
                    backtrack(row, col + 1)     
        def backtrack(row = 0, col = 0):
            if board[row][col] == '.':
                for d in range(1, 10):
                    if could_place(d, row, col):
                        place_number(d, row, col)
                        place_next_numbers(row, col)
                        if not sudoku_solved:
                            remove_number(d, row, col)
            else:
                place_next_numbers(row, col)  
        n = 3
        N = n * n
        box_index = lambda row, col: (row // n ) * n + col // n
        rows = [defaultdict(int) for i in range(N)]
        columns = [defaultdict(int) for i in range(N)]
        boxes = [defaultdict(int) for i in range(N)]
        for i in range(N):
            for j in range(N):
                if board[i][j] != '.': 
                    d = int(board[i][j])
                    place_number(d, i, j)
        sudoku_solved = False
        backtrack()

 

posted @ 2020-05-19 16:20  nil_f  阅读(204)  评论(0编辑  收藏  举报