解决数独

题目描述

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

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

数字 1-9 在每一行只能出现一次。

数字 1-9 在每一列只能出现一次。

数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。

空白格用 '.' 表示。

一个数独。

答案被标成红色。

Note:

给定的数独序列只包含数字 1-9 和字符 '.' 。

你可以假设给定的数独只有唯一解。

给定数独永远是 9x9 形式的。

输入格式:

[["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']]

难度分类

困难

算法分析

这道题的的思考是在9x9的格子里面找到未填充的数字,比如当找到第n个未填充数字的格子,此时尝试在里面填写1可以保证当前行不冲突,列不冲突,小方块不冲突,那么就在第n个格子里面填写1,然后查看第n+1个格子,如果第n+1个格子发现填写1-9都冲突,说明第n个格子填写1的情况下无法找到解,此时我们需要回到第n个格子,填写另外一个不冲突的数字。一直到能填充到第81个格子为止。

将上述解题思路转换为代码设计:

  1. 定义col_used存储对应列的值,col_used = [[[] for i in range(9)]]
  2. 定义row_used存储对应行的值row_used=[[] for i in range(9)]
  3. 定义box_used存储对应小方块的值box_used = [[[], [], []] for i in range(3)]
  4. 先遍历九宫格将已填充的数字记录进对应的行,列和小方块
  5. 通过定义i,j,遍历遍历九宫格,i代表行的index,j代表列的index,遍历九宫格
  6. 读取当前九宫格的值,当当前九宫格的值为“”.“”的时候进行以下操作:

a)     从1-9九个数字中选择一个数字(满足与当前行的数字不冲突,列的数字不冲突,小方块的数字不冲突)填入当前格子

b)     将这个填入的数字记录进对应的行,对应的列,对应的小方块

c)     判断在当前格子填写当前数字的基础上接下来的格子填充能否填满九宫格

d)     如果当前格子填写数字的基础上接下来的格子填充不能填满九宫格,则需要取消当前数字的填充即①取消已填充的数字,②将已填充的数字从对应的行取出,③将已填充的数字从对应的列取出,④将已填充的数字从对应的小方块取出。然后尝试填入其他数字

e)     通过True和False判断能否填写九宫格,仅当第81个格子填写完成(填写的过程中已经进行了条件校验)才返回True,否则返回False

7.如果当前格子已有数字直接查看下一个格子

要点:如果下层返回False,证明基于当前数字的填充没有解,重置九宫格,行,列,小方块状态,选取新的数字填充

代码示例

def solveSudoku(board):
# 记录某一列已使用的数字
row_used = [[] for i in range(9)]
# 记录某一行已使用的数字
col_used = [[] for i in range(9)]
# 记录某一个小方块已使用的数字
box_used = [[[], [], []] for i in range(3)]
# 首先记录九宫格中每行,每列,每一个小方块中已使用的数字,以用于填充数字的时候检查填充数字是否已被使用
for i in range(len(board)):
for j in range(len(board[i])):
if board[i][j] in "":
row_used[i].append(board[i][j])
col_used[j].append(board[i][j])
box_used[i // 3][j // 3].append(board[i][j])
def dfs(board, i=0, j=0):
# 从左到右一个一个格子的遍历九宫格,当某一行遍历结束遍历下一行的第一个格子
if j == 9:
i,j = i+1,0
if i == 9:
return True
# 当遍历到某一行为".",即需要填充数字的时候,此时需要从1-9九个数字中选择一个不冲突的数字填入当前格子
if board[i][j] ==".":
for num in (""):
# 填充格子的前提条件是行不冲突(每一行每一个数字仅出现一次),列不冲突(每一列每一个数字仅出现一次),小方块不冲突(每一小方块每一个数字仅出现一次)
if num not in row_used[i] and num not in col_used[j] and num not in box_used[i // 3][j // 3]:
# 填充格子的同时需要将当前数字计入对应的行,列,小方块,用于当其他格子填充的时候检查是否行,列,小方块冲突
row_used[i].append(num)
col_used[j].append(num)
box_used[i // 3][j // 3].append(num)
# 填充当前格子
board[i][j] = num
# 填充完成格子后此时检查基于当前格子已经填充了数字的基础上,填充下一个格子
if dfs(board,i,j+1):
return True
# 如果下一个格子填充失败,1-9九个数字都有冲突,证明当前格子填充当前数字不能找到有效的解,此时需要找到另外一个数字来填充当前格子,因此需要将当前格子恢复原始状态
# 恢复当前格子为未填充状态
row_used[i].pop()
col_used[j].pop()
box_used[i // 3][j // 3].pop()
board[i][j] = "."
return False
# 当遍历到某一格子为数字,直接查看下一个格子
else:
return dfs(board, i,j+1)
dfs(board)
board = [["","",".",".","",".",".",".","."],["",".",".","","","",".",".","."],[".","","",".",".",".",".","","."],["",".",".",".","",".",".",".",""],["",".",".","",".","",".",".",""],["",".",".",".","",".",".",".",""],[".","",".",".",".",".","","","."],[".",".",".","","","",".",".",""],[".",".",".",".","",".",".","",""]]
solveSudoku(board)
print(board)

考点分析

  1. 带返回值的回溯用法

20190924-LeetCode解数独题目分享的更多相关文章

  1. 20191030-带返回值的回溯算法Leetcode解数独

    题目描述 编写一个程序,通过已填充的空格来解决数独问题. 一个数独的解法需遵循如下规则: 数字 1-9 在每一行只能出现一次. 数字 1-9 在每一列只能出现一次. 数字 1-9 在每一个以粗实线分隔 ...

  2. leetcode 36 有效的数独 哈希表 unordered_set unordersd_map 保存状态 leetcode 37 解数独

    leetcode 36 感觉就是遍历. 保存好状态,就是各行各列还有各分区divide的情况 用数组做. 空间小时间大 class Solution { public: bool isValidSud ...

  3. Leetcode之回溯法专题-37. 解数独(Sudoku Solver)

    Leetcode之回溯法专题-37. 解数独(Sudoku Solver) 编写一个程序,通过已填充的空格来解决数独问题. 一个数独的解法需遵循如下规则: 数字 1-9 在每一行只能出现一次.数字 1 ...

  4. Java实现 LeetCode 37 解数独

    37. 解数独 编写一个程序,通过已填充的空格来解决数独问题. 一个数独的解法需遵循如下规则: 数字 1-9 在每一行只能出现一次. 数字 1-9 在每一列只能出现一次. 数字 1-9 在每一个以粗实 ...

  5. [leetcode]37. Sudoku Solver 解数独

    Write a program to solve a Sudoku puzzle by filling the empty cells. A sudoku solution must satisfy  ...

  6. [LeetCode] Sudoku Solver 解数独,递归,回溯

    Write a program to solve a Sudoku puzzle by filling the empty cells. Empty cells are indicated by th ...

  7. [leetcode] 37. 解数独(Java)(dfs,递归,回溯)

    37. 解数独 1A 这个题其实15分钟左右就敲出来并且对了...但是由于我输错了一个数..导致我白白debug一个多小时.. 没啥难度,练递归-dfs的好题 class Solution { pri ...

  8. LeetCode37 使用回溯算法实现解数独,详解剪枝优化

    本文始发于个人公众号:TechFlow,原创不易,求个关注 数独是一个老少咸宜的益智游戏,一直有很多拥趸.但是有没有想过,数独游戏是怎么创造出来的呢?当然我们可以每一关都人工设置,但是显然这工作量非常 ...

  9. 【原创】一个基于简单剪枝的DFS解数独程序

    问题来源:leetCode Sudoku Solver Write a program to solve aSudoku puzzle by filling the empty cells. Empt ...

随机推荐

  1. java 通过runtime 调用python 不显示python运行内容的bug

    先说下上面问题的原因,上面问题是因为python中用到了第三方的类库,你的电脑上没有那个类库,所以程序没有运行,在控制台也就看不到输出.只要导入那个类库就好... python 导入类库,可以单独下载 ...

  2. Java核心复习——J.U.C LinkedBlockingQueue源码分析

    参考文档 LinkedBlockingQueue和ArrayBlockingQueue的异同

  3. TortoiseGit的安装与配置

    1. 简介 TortoiseGit是Tortoise提供的Git版本可视化工具,简化Git记忆命令行的过程,将命令行可视化. 2. 下载 官网:https://tortoisegit.org/down ...

  4. java maven scope compile,provide,system,test,runtime

    在一个maven项目中,如果存在编译需要而发布不需要的jar包,可以用scope标签,值设为provided.如下: <dependency>            <groupId ...

  5. Vue源码分析(一) : new Vue() 做了什么

    Vue源码分析(一) : new Vue() 做了什么 author: @TiffanysBear 在了解new Vue做了什么之前,我们先对Vue源码做一些基础的了解,如果你已经对基础的源码目录设计 ...

  6. oracle之case

    使用oracle时,不免会用到判断后转换为要展示的值,这里常用case,如下: SELECT (case ) then 'yes' ) then 'no' else 'other' end) --no ...

  7. php如何生成 uuid(总结)

    php如何生成 uuid(总结) 一.总结 一句话总结: UUID的全拼为“Universally Unique Identifier”,可以译为“通用唯一识别码”. UUID是指在一台机器上生成的数 ...

  8. 使用INDY解决BASE64回车换行问题

    使用INDY解决BASE64回车换行问题 使用DELPHI EncodeStream(),对流数据进行BASE64编译以后,每隔75个字符,就会添加回车换行符(#$D#$A),这会造成许多问题. 网上 ...

  9. 阶段5 3.微服务项目【学成在线】_day16 Spring Security Oauth2_14-认证接口开发-需求分析

    4 认证接口开发 4.1 需求分析 用户登录的流程图如下: 执行流程: 1.用户登录,请求认证服务 2.认证服务认证通过,生成jwt令牌,将jwt令牌及相关信息写入Redis,并且将身份令牌写入coo ...

  10. ALV显示金额字段值扩大100倍

    内表数据 物料                  库位          期末庫存金額F0D7004DSA   1PYF       701410.944F0D7004DSA   1SNT      ...