LeetCode刷题(python版)——Topic37解数独

一、题设

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

数独的解法需 遵循如下规则

  1. 数字 1-9 在每一行只能出现一次。
  2. 数字 1-9 在每一列只能出现一次。
  3. 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)

数独部分空格内已填入了数字,空白格用 '.' 表示。

示例 1:

输入:board = 
[["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"]]
输出:
[["5","3","4","6","7","8","9","1","2"],
["6","7","2","1","9","5","3","4","8"],
["1","9","8","3","4","2","5","6","7"],
["8","5","9","7","6","1","4","2","3"],
["4","2","6","8","5","3","7","9","1"],
["7","1","3","9","2","4","8","5","6"],
["9","6","1","5","3","7","2","8","4"],
["2","8","7","4","1","9","6","3","5"],
["3","4","5","2","8","6","1","7","9"]]
解释:输入的数独如上图所示,唯一有效的解决方案如下所示:

二、基本思路

        本题使用 回溯 (递归)+ 深度遍历算法(dfs) 可较为方便的求解。

        1. 首先将board数组转变为数字数组table运算较为简便,等到所有对于矩阵table的运算结束之后再转变成字符数组board。

        2. 其次从(x = 0,y = 0)处开始dfs,分别产生以下几种情况:

          2.1 当x = 9时,即为第十行,则意味着全部的遍历填数早已结束,则返回True

          2.2 当y = 9时,即为每行的第十列,则意味着每行到达了尽头,应该换行了,则递归返回下一行第一个数:dfs(x+1,0)

          2.3 当处理后的table[x][y]不为0时,即代表该坐标(x,y)在数独中是初始值,则跳过看下一个位置是否为空:dfs(x,y+1)

          2.4 当以上全部的三种情况处理好之后,可以开始填入数据了,则从0~9挨个尝试填入,若当前数val不满足:行唯一、列唯一以及九宫格内唯一这三个条件时,则将当前table[x][y]重置为0,尝试下个数val+1;若三个条件同时满足,既可以填入val并当所有的dfs(x,y+1)成立时,这次填入的所有数全部成立,返回True。

                

三、代码实现

def solveSudoku(self, board):
        # tag1将board先转成数字数组方便存放
        table = [([0] * 9) for i in range(9)]
        # dfs func start……
        def dfs(x,y):
            # 如果x是第十行(table已全部遍历结束)
            if x == 9:
                return True
            # 如果y是9,则该换行了
            if y == 9:
                return dfs(x+1,0)
            # 如果(x,y)有数字,则跳转到下一个格子
            if table[x][y] != 0:
                return dfs(x,y+1)
            # val代表预计填入0~9的数字
            for val in range(10):
                # 看是否满足三个条件,有一个不满足标志flag记为false
                flag = True 
                # 行是否唯一
                for col in range(9):
                    if table[x][col] == val:
                        flag = False
                        break
                # 列是否唯一
                for row in range(9):
                    if table[row][y] == val:
                        flag = False
                        break
                # (xx,yy)代表每个 3 * 3 方格起点坐标
                # 九宫格内是否唯一
                xx,yy = x / 3 * 3 , y / 3 * 3
                for i in range(3):
                    for j in range(3):
                        if table[xx + i][yy + j] == val:
                            flag = False
                            break
                # 若唯一
                if flag == True:
                    table[x][y] = val #val可填入
                    if dfs(x,y+1):#全部填入成功
                        return True
                    table[x][y] = 0 #当前val填入失败,尝试下一个val
        # dfs func end……
        # main func start……
        for i in range(9):
            for j in range(9):
                if board[i][j] != '.':
                    table[i][j] = int(board[i][j])
        dfs(0,0)
        # tag1将table先转成字符数组board返回
        for i in range(9):
            for j in range(9):
                board[i][j] = str(table[i][j])
        # main func end……

四、效率总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值