编写一个程序,通过填充空格来解决数独问题。
一个数独的解法需遵循如下规则:
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
空白格用 ‘.’ 表示。
一个数独。
答案被标成红色。
提示:
- 给定的数独序列只包含数字 1-9 和字符 ‘.’ 。
- 你可以假设给定的数独只有唯一解。
- 给定数独永远是 9x9 形式的。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sudoku-solver
解题思路
十字交叉双向循环链表是一种特殊的数据结构,专门用来解决精确覆盖的问题,相关资料可自行百度。
对于任何复杂的数独,任何语言均可在100ms内解出。
比如下面这个数独,官方目前给出的三个方法用python解时都需要几秒甚至几十秒。
[“080000600”,
“000400009”,
“070000805”,
“400000000”,
“030060090”,
“000720100”,
“093200064”,
“810300000”,
“000005000”]
下面给出用DLX解数独的详细代码(python版),解决困难的数独只需要60ms。
代码
class DLX:
"""
十字交叉双向循环链表
"""
def __init__(self, n):
"""
:param n: 数独的阶数
"""
self.n = n
self.m = n ** 2 * n ** 2 * 4 + 1 # 总共的列数(标注节点数+头节点)
self.max_nums = n ** 2 * n ** 2 * n ** 2 * 4 + self.m # 最大节点编号
# 用下标表示节点编号,下标0表示节点0(即头节点),下标1表示节点1,以此类推...
self.u = [0 for _ in range(self.max_nums)] # 记录节点的上链接点
self.d = [0 for _ in range(self.max_nums)] # 记录节点的下链接点
self.l = [0 for _ in range(self.max_nums)] # 记录节点的左链接点
self.r = [0 for _ in range(self.max_nums)] # 记录节点的右链接点
self.row = [0 for _ in range(self.max_nums)] # 记录节点所在的行
self.col = [0 for _ in range(self.max_nums)] # 记录节点所在的列
# 设置首行的上下左右链接关系
for i in range(self.m):
self.u[i] = i
self.d[i] = i
self.r[i] = i + 1
self.l[i] = i - 1
self.row[i] = 0
self.col[i] = i
self.head = 0
self.l[self