【算法数据结构】leetcode37 解数独


37. 解数独 - 力扣(LeetCode)

题目描述:

题目要求每一行 ,每一列,每个3*3 的子框只能出现一次。每个格子的数字范围1-9.

需要遍历每个空格填入可能的数字,并验证符合规则。如果符合就填入,不符合就回溯。

解法: 

回溯算法通常用于解决这种需要试错的问题。当发现当前路径无解时候,返回上一步重新选择。

需要遍历每个空格,找到需要填写的空格,对每个空格尝试填入1-9,检查这个数字是否满足行,列 ,子框的要求。如果满足就填入这个数字,递归进行下一个空格,如果后续处理中,发现无法填入下去,就需要回溯。恢复这个空格的状态,尝试下一个可能的数字。

检查某个数字是否可以填入当前位置

对于 位置(i,i)需要检查i 行,j 列,所在的子框是否有这个数字,属于第几个子框可以用 (i/3 )*3,(j/3 )*3来确定 。i=4   4/3=1    1*3=3    ,起始行是3 ,遍历这个3*3的子框。

对于每个空格最多检查1-9个数字。,每个数字需要检查三个方向,最坏情况可能出现重复检查。

优化方法

用哈希表或者数据记录行,列,子框。已经出现的数字。用3个二维数组,记录rowi 表示第i行是否存在数组num,colj 表示第j 列是否存在数据num,boxk 表示第k 个子框中是否存咋这个数字num,

k 可以通过  i//3*3 +j//3 来计算 

i=0 ,j=0   ,k=0

i=3,j=3 ,k=4  在第四个子框。

预处理这三个数组,遍历整个数独,对这个对每个非空的格子,将对应的行列,子框中盖数字标记为存在。比如broad_i 为5 ,那么需要row_i  设置为true ,col_j 设置为true ,box_k (k为子框的索引)设置为true。

对每个空格尝试填入1-9 数字中的一个,

初始化  9X10 数组 其中索引 0不用 

步骤

1. 预处理三个数组row、col、box,记录每个行、列、子框中已经存在的数字。

2. 收集所有需要填写的空格的位置,存入一个列表spaces。

3. 编写一个回溯函数,参数是当前处理到spaces中的第pos个位置。当pos等于spaces的长度时,说明已经填完所有空格,返回True。

4. 对于当前处理的空格位置(i,j),尝试填入1到9中的一个数字d。如果该数字满足row[i][d]、col[j][d]、box[k][d]都为False,那么将该数字填入,并更新这三个数组的状态。然后递归处理pos+1的位置。如果递归返回True,说明后续的填写都成功,那么当前的选择是正确的,直接返回True。如果递归返回False,则说明后续无法完成,需要回溯,恢复三个数组的状态,并将board[i][j]恢复为'.',然后尝试下一个数字。

5. 如果所有数字都尝试过且都不行,则返回False,触发上一层递归的回溯。

这样,当递归函数返回True时,说明已经找到解,此时board已经被正确填充。

    # 初始化 3个数组row = [[False] * 10 for i in range(9)]print(row)  # 每行十个元素col = [[False] * 10 for i in range(9)]box = [[False] * 10 for i in range(9)]

[[False, False, False, False, False, False, False, False, False, False],[False, False, False, False, False, False, False, False, False, False],[False, False, False, False, False, False, False, False, False, False],[False, False, False, False, False, False, False, False, False, False], 
[False, False, False, False, False, False, False, False, False, False],[False, False, False, False, False, False, False, False, False, False], 
[False, False, False, False, False, False, False, False, False, False], 
[False, False, False, False, False, False, False, False, False, False],[False, False, False, False, False, False, False, False, False, False]]

 遍历数组填充已经有的数字 spaces 用于记录空格的位置

# 遍历整个数组 记录每个行 ,列子框中已经存在的数字spaces = []for i in range(9):for j in range(9):if board[i][j] != '.':d = int(board[i][j])row[i][d] = Truecol[j][d] = Truek = (i // 3) * 3 + (j // 3)box[k][d] = True  # 第k 个箱子的d 是否存在# 保存空格的位置到spaceselse:spaces.append((i, j))print("空格的位置", spaces)

空格的位置 [(0, 2), (0, 3), (0, 5), (0, 6), (0, 7), (0, 8), (1, 1), (1, 2), (1, 6), (1, 7), (1, 8), (2, 0), (2, 3), (2, 4), (2, 5), (2, 6), (2, 8), (3, 1), (3, 2), (3, 3), (3, 5), (3, 6), (3, 7), (4, 1), (4, 2), (4, 4), (4, 6), (4, 7), (5, 1), (5, 2), (5, 3), (5, 5), (5, 6), (5, 7), (6, 0), (6, 2), (6, 3), (6, 4), (6, 5), (6, 8), (7, 0), (7, 1), (7, 2), (7, 6), (7, 7), (8, 0), (8, 1), (8, 2), (8, 3), (8, 5), (8, 6)]


d = int(board[i][j])  填充的数字作为下标

  row:  row[i][d]=True

[[False, False, False, True(3), False, True(5), False, True(7), False, False],[False, True(1), False, False, False, True(5), True(6), False, False, True(9)],[False, False, False, False, False, False, True(6), False, True(8), True(9)], 
[False, False, False, True(3), False, False, True(6), False, True(8), False],[False, True(1), False, True(3), True(4), False, False, False, True(8), False],[False, False, True(2), False, False, False, True(6), True(7), False, False], 
[False, False, True(2), False, False, False, True(6), False, True(8), False],[False, True(1), False, False, True(4), True(5)), False, False, False, True(9)],[False, False, False, False, False, False, False, True(7), True(8), True(9)]]

col : col[j][d]=true   纵坐标作为 行 d作为列 

第一列   4 5  6 7 8

 [False, False, False, False, True(4), True(5), True(6), True(7), True(8), False]

[[False, False, False, False, True(4), True(5), True(6), True(7), True(8), False], 
[False, False, False, True, False, False, True, False, False, True], 
[False, False, False, False, False, False, False, False, True, False],[False, True, False, False, True, False, False, False, True, False],[False, True, True, False, False, False, True, True, True, True], 
[False, False, False, True, False, True, False, False, False, True],[False, False, True, False, False, False, False, False, False, False], 
[False, False, False, False, False, False, True, True, True, False], 
[False, True, False, True, False, True, True, False, False, True]]

   box :      k = (i // 3) * 3 + (j // 3)
                box[k][d] = True  # 第k 个箱子的d 是否存在

  例如  board[4][3]=8   k=(4//3)*3 +(3//1) =4  第4个子框  第8个标记为true

[[False, False, False, True, False, True, True, False, True, True], 
[False, True, False, False, False, True, False, True, False, True],[False, False, False, False, False, False, True, False, False, False], 
[False, False, False, False, True, False, False, True, True, False],[False, False, True, True, False, False, True, False, True(8), False], 
[False, True, False, True, False, False, True, False, False, False],[False, False, False, False, False, False, True, False, False, False],[False, True, False, False, True, False, False, False, True, True], 
[False, False, True, False, False, True, False, True, True, True]]

定义回溯

# 定义回溯def backtrack(pos):print("pos", pos)if pos == len(spaces):  # 当pos 等于spaces长度时候说明已经填写完 ,返回trueprint("结果", board)return Truei, j = spaces[pos]k = (i // 3) * 3 + (j // 3)for d in range(1, 10):  # 对这个位置尝试填充1-9if not row[i][d] and not col[j][d] and not box[k][d]:  # 满足为false 时候填入row[i][d] = Truecol[j][d] = Truebox[k][d] = Trueboard[i][j] = str(d)if backtrack(pos + 1):return True# 回溯row[i][d] = Falsecol[j][d] = Falsebox[k][d] = Falseboard[i][j] = '.'  # 恢复空格return Falsebacktrack(0)

代码 

class Solution:def solveSudoku(self, board: List[List[str]]) -> None:"""Do not return anything, modify board in-place instead."""# 初始化三个数组row=[[False] *10 for _ in range(9)]col=[[False] *10 for _ in range(9)]box=[[False] *10 for _ in range(9)]spaces=[] # 记录空格位置# 遍历数组填充已经有的数字for i in range(9):for j in range(9):if board[i][j]!='.':d=int(board[i][j])row[i][d]=Truecol[j][d]=Truek=(i//3)*3+(j//3)box[k][d]=Trueelse:spaces.append((i,j)) # 记录空格的坐标def  backtrack(pos):if pos ==len(spaces):#遍历完了所有空格return Truei,j=spaces[pos] # 取出当前位置的空格坐标k=(i//3)*3+(j//3)for d in range(1,10):  # 尝试对该位置填充1-9if row[i][d]==False and col[j][d]==False and box[k][d]==False:row[i][d]=Truecol[j][d]=Truebox[k][d]=Trueboard[i][j]=str(d)if backtrack(pos+1):return True#不满足  回溯row[i][d]=Falsecol[j][d]=Falsebox[k][d]=Falseboard[i][j]='.' return Falsebacktrack(0)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/79776.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vector的学习

vector简介 vector的相关文档对于想深入了解的同学可以参考这个文档进行学习。 vector是表示可变大小数组的序列容器。 就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不…

Vue常用指令入门

1. v-for 作用&#xff1a;用于遍历对象或数组 注意&#xff1a;需要提供key属性&#xff0c;可以提高性能和避免渲染错误&#xff0c;值通常为index或item.id <li v-for"(item, index) in items" :key"index">{{ item }} </li>2. v-if,v-el…

在机器视觉检测中为何选择线阵工业相机?

线阵工业相机&#xff0c;顾名思义是成像传感器呈“线”状的。虽然也是二维图像&#xff0c;但极宽&#xff0c;几千个像素的宽度&#xff0c;而高度却只有几个像素的而已。一般在两种情况下使用这种相机&#xff1a; 1. 被测视野为细长的带状&#xff0c;多用于滚筒上检测的问…

线性DP:最长上升子序列(子序列可不连续,子数组必须连续)

目录 Q1&#xff1a;简单遍历 Q2&#xff1a;变式&#xff08;加大数据量&#xff09; Q1&#xff1a;简单遍历 Dp问题 状态表示 f(i,j) 集合所有以第i个数结尾的上升子序列集合-f(i,j)的值存的是什么序列长度最大值max- 状态计算 &#xff08;其实质是集合的划分&#xff09;…

【Web前端技术】第二节—HTML标签(上)

hello&#xff01;好久不见—— 做出一个属于自己的网站&#xff01; 云边有个稻草人-个人主页 Web前端技术—本篇文章所属专栏 目录 一、HTML 语法规范 1.1 基本语法概述 1.2 标签关系 二、HTML 基本结构标签 2.1 第一个 HTML 网页 2.2 基本结构标签总结 三、网页开发…

论文降重GPT指令-实侧有效从98%降低到8%

步骤1&#xff1a;文本接收 指令&#xff1a; 请用户提供需要优化的文本内容。 对文本进行初步分析&#xff0c;识别文本的基本结构和风格。 操作&#xff1a; 接收并分析用户提交的文本。 步骤2&#xff1a;文本优化 2.1 连接词处理 指令&#xff1a; 删除或替换连接词&#x…

Jsp技术入门指南【九】详细讲解JSTL

Jsp技术入门指南【九】详细讲解JSTL 前言一、什么是JSTL&#xff1f;&#xff08;JavaServer Pages Standard Tag Library&#xff09;二、使用JSTL前的准备三、核心标签库常用标签详解1. <c:out>&#xff1a;输出内容&#xff08;替代<% %>&#xff09;2. <c:i…

Linux操作系统--进程的创建和终止

目录 1.进程创建 1.1fork()函数初识 1.2写时拷贝 1. 提升系统效率 2. 隔离错误影响 3. 支持并行计算 2.进程终止&#xff1a; 2.1进程退出场景&#xff1a; 2.2进程常见退出方法&#xff1a; 2.3_exit()系统调用接口 2.4exit函数 2.5return退出 1.进程创建 1.1for…

OSPF综合实验——企业边界路由器、LSA收敛

IP划分粗略记号&#xff0c;方便后续配置 配置IP和环回--->ISP的IP配置和cheat认证---->配置OSPF和RIP---->企业边界路由网段汇总---->特殊区域---> 缺省路由&#xff0c;重分发---->nat配置---->实现全网通 路由器配置IP和环回地址 <Huawei>sys…

Java【网络原理】(4)HTTP协议

目录 1.前言 2.正文 2.1自定义协议 2.2HTTP协议 2.2.1抓包工具 2.2.2请求响应格式 2.2.2.1URL 2.2.2.2urlencode 2.2.3认识方法 2.2.3.1GET与POST 2.2.3.2PUT与DELETE 2.2.4请求头关键属性 3.小结 1.前言 哈喽大家好啊&#xff0c;今天来继续给大家带来Java中网络…

Android学习总结之APK打包流程

一、预处理阶段&#xff08;编译前准备&#xff09; 1. AIDL 文件处理&#xff08;进程间通信基础&#xff09; 流程&#xff1a; 用于实现 Android 系统中不同进程间的通信&#xff08;IPC&#xff09;。在项目构建时&#xff0c;AIDL 编译器会将 .aidl 文件编译为 Java 接口…

BDO分厂积极开展“五个一”安全活动

BDO分厂为规范化学习“五个一”活动主题&#xff0c;按照“上下联动、分头准备 、差异管理、资源共享”的原则&#xff0c;全面激活班组安全活动管理新模式&#xff0c;正在积极开展班组安全活动&#xff0c;以单元班组形式对每个班组每周组织一次“五个一”安全活动。 丁二醇单…

【音视频】FLV格式分析

FLV概述 FLV(Flash Video)是Adobe公司推出的⼀种流媒体格式&#xff0c;由于其封装后的⾳视频⽂件体积⼩、封装简单等特点&#xff0c;⾮常适合于互联⽹上使⽤。⽬前主流的视频⽹站基本都⽀持FLV。采⽤FLV格式封装的⽂件后缀为.flv。 FLV封装格式是由⼀个⽂件头(file header)和…

Java表达式1.0

Java开发工具 在当今的Java开发领域&#xff0c;IntelliJ IDEA已然成为了众多开发者心目中的首选利器&#xff0c;它被广泛认为是目前Java开发效率最快的IDE工具。这款备受瞩目的开发工具是由JetBrains公司精心打造的&#xff0c;而JetBrains公司总部位于风景如画的捷克共和国首…

Map遍历

第一种遍历方式键找值&#xff1a; 增强for循环&#xff1a; 通过获取元素中的键&#xff0c;get到对应的值&#xff0c;通过增强for循环获取集合里的键&#xff0c;然后用get方法通过键获取值 代码演示&#xff1a; import java.text.ParseException; import java.util.*;…

内网穿透服务器—FRP

某天某刻空闲的时候跟同事聊的本地的存储服务如果我想让其他公网内的用户使用&#xff08;这个存储服务只是一个临时文件传递站&#xff0c;碎文件&#xff0c;安全低的&#xff09;&#xff0c;然后我们就探讨到了FRP一个比较久远的技术&#xff0c;来做内网穿透&#xff0c;下…

力扣每日打卡16 781. 森林中的兔子(中等)

力扣 781. 森林中的兔子 中等 前言一、题目内容二、解题方法1. 哈希函数&#xff08;来自评论区大佬的解题方法&#xff09;2.官方题解2.1 方法一&#xff1a;贪心 前言 这是刷算法题的第十六天&#xff0c;用到的语言是JS 题目&#xff1a;力扣 781. 森林中的兔子 (中等) 一、…

基于深度学习的线性预测:创新应用与挑战

一、引言 1.1 研究背景 深度学习作为人工智能领域的重要分支&#xff0c;近年来在各个领域都取得了显著的进展。在线性预测领域&#xff0c;深度学习也逐渐兴起并展现出强大的潜力。传统的线性预测方法在处理复杂数据和动态变化的情况时往往存在一定的局限性。而深度学习凭借…

黑马点评redis改 part 3

优惠券秒杀 全局唯一id 每个店铺都可以发布优惠券&#xff1a; 当用户抢购时&#xff0c;就会生成订单并保存到tb_voucher_order这张表中&#xff0c;而订单表如果使用数据库自增ID就存在一些问题&#xff1a;实际开发中数据库ID一般不会参与业务逻辑 增加一个订单号字段就好…

低代码开发平台:企业数字化转型的加速器

一、引言 在数字化时代&#xff0c;企业的转型需求日益迫切。为了在激烈的市场竞争中保持领先地位&#xff0c;企业需要快速响应市场变化、优化业务流程、提升运营效率。然而&#xff0c;传统的软件开发模式往往面临开发周期长、成本高、灵活性差等问题&#xff0c;难以满足企业…