37解数独

题目: 编写一个程序,通过已填充的空格来解决数独问题。

来源: https://leetcode-cn.com/problems/sudoku-solver/

法一: 自己的代码

思路: 利用回溯法典型的模板,对没有填空的逐个遍历,测试用例的时候一定要注意边界条件,这个题的边界条件是九宫格的最后一个空,要分空和非空进行测试.回溯的时候有两种情况需要返回,一是全部填完了需要返回结果,二是某个格子没有可以填的数字,这时需要结束本次回溯,当用回溯法只返回一种情况的时候(如60题第K个排列),这时要把回溯函数写在return后面,当有两种及以上情况时,可以返回不同的值,用if语句进行判断,分别处理.

# 执行用时 :260 ms, 在所有 python3 提交中击败了34.63% 的用户
# 内存消耗 :12.8 MB, 在所有 python3 提交中击败了97.83%的用户
import typing as List
class Solution:
    def solveSudoku(self, board):
        def cannot_place(row,col):
            # 如果为'.',说明可以放置数字,返回False,如果到最后一个或超出边界了,说明所有的都填满了
            if (board[row][col] == '.') or ([row,col] in [[8,8],[9,0]]):
                return False
            else:
                return True
        def move_to_next_number(row,col):
            # 注意这里边界条件的设定,非常重要,很容易错
            if col<8:
                return row,col+1
            # 只有到了每行的最后一列,才会执行这个判断,
            elif row<8:
                col = 0
                return row+1,col
            else:
                return 8,8
        # 求(row,col)处可以填的数字
        def diff_set(row,col):
            # a记录位置(row,col)所在行和列的数字
            a = board[row] + [board[i][col] for i in range(9)]
            # k记录位置(row,col)所在九宫格的数字
            p = int(row / 3)
            q = int(col / 3)
            dict = {0: (0, 3), 1: (3, 6), 2: (6, 9)}
            m, n = dict[p]
            u, v = dict[q]
            a = sum([i[u:v] for i in board[m:n]], []) + a
            a = set(a)
            if '.' in a:
                set(a).remove('.')
            b = [str(i+1) for i in range(9)]
            return list(set(b) - set(a))
        def backtrack(row,col):
            # 如果当前位置有数字,则移到下一个
            while cannot_place(row,col):
                row,col = move_to_next_number(row,col)
            # 如果到最后一个格子了,且该格不为空,则结束
            if (row==8) & (col==8) & (board[8][8] != '.'):
                return True
            # 利用三个限定条件,减少数字的遍历数目
            nums = diff_set(row,col)
            # 如果这个格子没有数字可以填了,则返回False回溯
            if len(nums) == 0:
                return False
            for i in nums:
                board[row][col] = i
                # 这里为了避免重复判断,提前将空格移动到下一个,当前空格已经有数字了,
                # 无需在下一次的回溯中用while判断了,由于这里没有用while,要放止越界
                p,q = move_to_next_number(row,col)
                # 这里的写法非常巧妙,因为回溯函数有两种情况需要中断,所以用一个if条件来判断
                # 如果遇到nums为0,无法继续回溯,则返回False进行下一个,
                # 如果是找到合适的了,则返回True,结束程序
                if backtrack(p,q):
                    return True
                board[row][col] = '.'
        backtrack(row=0,col=0)
if __name__ == '__main__':
    # data=[["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"]]
    data = [[".",".","9","7","4","8",".",".","."],
            ["7",".",".",".",".",".",".",".","."],
            [".","2",".","1",".","9",".",".","."],
            [".",".","7",".",".",".","2","4","."],
            [".","6","4",".","1",".","5","9","."],
            [".","9","8",".",".",".","3",".","."],
            [".",".",".","8",".","3",".","2","."],
            [".",".",".",".",".",".",".",".","6"],
            [".",".",".","2","7","5","9",".","."]]
    duixiang = Solution()
    duixiang.solveSudoku(data)
    print(data)
View Code

法二: 官方代码

思路:

猜你喜欢

转载自www.cnblogs.com/xxswkl/p/12077616.html