【蓝桥杯速成】| 13.回溯通关 解数读

server/2025/3/30 7:19:58/

题目一:解数读

问题描述

37. 解数独 - 力扣(LeetCode)

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

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

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

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

提示:

  • board.length == 9
  • board[i].length == 9
  • board[i][j] 是一位数字或者 '.'
  • 题目数据 保证 输入数独仅有一个解

解题思路

看到这一题第一反应是和N皇后有点类似

开始用同样的思路套

但总觉得哪里好像漏了点啥

或者说感觉实现不了在每个格子填上正确的数,要考虑和顾忌的因素有点多了

但这就是回溯算法的本领所在!

往简单了想,剩下的交给递归和回溯!

那么重新品一下题目,由于题目已经规定 

  • board.length == 9
  • board[i].length == 9

 就是说这个数独大棋盘是9×9的

然后它会在某些位置给出数字,要求我们去填剩下的格子

简单点看就是不要太在意它是个二维数组

我们要做的仅仅是在这81个数字中空缺的位置按顺序填上合适的数字

到底怎么样合适有isValid函数按照规则判断

不合适也有递归、遍历替我们处理

如果你想问:怎么知道这一格填下去的数字不会影响后续呢?

因为你在填的时候是一直往后一个空格走的,

如果这个plan不合适,它会回溯后换一个分支,就直接倒回去修改,

那这一块让我们用手写画出还是比较复杂的

但对计算机来说不困难,笨笨的暴力搜索就好啦,没有啥技术含量的

ok差不多可以开始敲代码啦!

还是走回溯三部曲

1.确定函数返回值及参数

由于这一题我们会直接在board上修改,并且只有一个解(题目数据 保证 输入数独仅有一个解)

那我们递归过程就需要专注于合不合法,对不对即可,那返回值应当是bool

参数就是需要修改的board,

为什么没有row,或者col呢?请往下看就知道了!

2.确定终止条件

这一题想要终止得到最后结果,那就是正确填完所有格子,

那么我们遍历结束实际上整个流程也结束了,没有必要再加终止条件

3.遍历逻辑

上面讲到我们可以视为在填81个格子中空缺的部分

那么为了明确表示空格位置我们应该用两个for循环嵌套实现

for(int i=0;i<9;i++){//行

        for(int j=0;j<9;j++){//列

有数字有空格,需要处理空格那肯定要先找到

所以加上判断空格的语句是空格那么我们就要继续 

if ( board [ i ][ j ] == ' . ')

或者选择跳过有数字的格子

if(board [ i ][ j ] != ' . ')         continue;

 在空格位置我们就要尝试填入数字,

如果作为一个完全不会数独的人来说

他最可能做的就是从1~9挨个试一遍

我们让计算机学他就行

for(int k='1';k<='9';k++)//注意是char

选择一个数字后就要进行合法性判断,那么在这个循环中加入if语句检验

if(isValid(.....))//合法性验证函数等会解决 

如果当前填这个数合适,

那么我们就需要填入这个数,再递归填下一个空,再回溯

board[i][j]=k;

backtracking(board);

board[i][j]='.';

 其中backtracking(board);语句是一直往下填,填满81格

但我们要的是正确才继续,并且需要返回给上一层,错误就及时止损

所以这一句应该改为

if(backtracking(board))        return true

如果这个递归结束,在当前格试完9个数字,没有合适的

就应该立即返回false

 for(int k='1';k<='9';k++){

...

}

return false

那么这整个函数最后肯定还是要一个完整的返回值的

所以在最后要加上返回true,表示完成数独!返回提交答案

return true; 

在主函数中直接调用backtracking函数即可

backtracking(board) ;

 

4.验证合法性

验证函数那我们最后要的肯定是对or错

所以返回值应该是bool型

验证这个格子数值是否合法,

那么需要这整个数独填的咋样了,检查的是哪一格,现在填的什么数

故参数为board,i,j

bool isValid(vector<vector<char>>& board,int row,int col,int value) 

需要满足要求:

1)同一行不存在重复的

那就是在row相等的元素中,从0位开始检查是否有和value值一样的

如果有,就返回false

 for(int j=0; j<9; j++){

        if(board[row][j]==value){

                return false;

        }

}

 2)同一列不存在重复的

逻辑一样,需要检查在col相等的元素中,从0位开始是否有和value值一样的

如果有,就返回false

if(int i=0;i<9;i++){

        if(board[i][col]==value){

                return false;

        }

}

注意!以上都要检查一整行,而不是像N皇后只检查前面部分

数独可能后面有给出数字,那么我们遍历整行才能快速排掉不正确方案

否则可能会导致大量无效的递归调用,最后就超时了!!!

3) 3x3 宫内不存在重复的

这一步稍微有点复杂,但就是要算出它是哪一小片,遍历这一片即可

用/3可以得到片区的序号再由此计算起始行号和起始列号

例如board[4][6],第二排左边片区

行号4/3=1,起始行号就是1*3,终止行号就是i*3+2

列号6/3=2,起始列号就是2*3,终止列号就是2*3+2

除此以外遍历时要注意避开当前检验的格子,不然肯定有一样的(自己和自己一样) 

for(int i=row/3*3;i<=row/3*3+2;i++){

        for(int j=col/3*3;j<=col/3*3+2;j++){

        if(i!=row && j!==col && board[i][j]==value){

                return false;

        } 

}       

 都没违反规则则返回true

return true;

完整代码看下面! 

code

class Solution {
private:bool isValid(vector<vector<char>>& board,int row,int col,int value){for(int j=0;j<9;j++){if(board[row][j]==value){return false;}}for(int i=0;i<9;i++){if(board[i][col]==value){return false;}}for(int i=row/3*3;i<=row/3*3+2;i++){for(int j=col/3*3;j<=col/3*3+2;j++){if(board[i][j]==value){return false;}}}return true;}bool backtracking(vector<vector<char>>& board){for(int i=0;i<9;i++){for(int j=0;j<9;j++){if(board[i][j]!='.'){continue;}for(int k='1';k<='9';k++){if(isValid(board,i,j,k)){board[i][j]=k;if(backtracking(board)) return true;board[i][j]='.';}}return false;}}return true;}
public:void solveSudoku(vector<vector<char>>& board) {backtracking(board);}
};

 


http://www.ppmy.cn/server/179468.html

相关文章

【0】数据结构的绪论章

目录标题 逻辑结构物理结构算法算法的五特性算法的设计目标算法的时间复杂度 计算机科学家Niklaus Wirth曾提出&#xff1a;算法数据结构程序设计 逻辑结构 第一种分类方法 集合结构&#xff1a;数据元素属于一个集合 线性结构&#xff1a;数据元素存在一对一的线性关系 树状…

kettle插件-mysql8数据库插件

场景&#xff1a;群里有小伙伴反馈kettle 7.x版本不能自动连接mysql8&#xff0c;安排&#xff01;&#xff01;&#xff01; 1、将mysql8的驱动包mysql-connector-java-8.0.20.jar丢到kettle的lib目录下&#xff0c;重启spoon。 2、配置数据库连接&#xff0c;提示驱动类不对…

第三十一篇 数据仓库(DW)与商业智能(BI)架构设计与实践指南

目录 一、DW/BI架构核心理论与选型策略1.1 主流架构模式对比&#xff08;1&#xff09;Kimball维度建模架构&#xff08;2&#xff09;Inmon企业工厂架构&#xff08;3&#xff09;混合架构 二、架构设计方法论与实施步骤2.1 维度建模实战指南&#xff08;1&#xff09;模型选择…

比特币等虚拟货币实时价格使用说明,数字货币价格获取,k线获取,实时价格获取

数据截图 k线数据 websocket 实时价格数据 根据这些数据可以做出自己的产品 获取时间段内的k线数据 在开始之前&#xff0c;你需要知道的知识&#xff1a; 币种缩写英文名币种IDBTCBitcoinbitcoinETHEthereumethereumEOSEOSeosUSDTTethertetherLTCLitecoinlitecoinUSDDol…

文件上传绕过的小点总结(6)

14.文件上传&#xff08;文件包含漏洞&#xff09;二次渲染 很多服务器为了防止代码嵌入图片&#xff0c;通常会将上传的图片进行重新生成处理&#xff0c;包括文件格式转换等等&#xff0c;嵌入的恶意代码很容易被改掉。于是产生了二次渲染&#xff0c;二次渲染的原理就是找到…

通过AOP技术拦截Spring Boot中异步方法执行,并动态调整线程池的线程数以应对不同任务的需求

在 Spring Boot 项目中&#xff0c;结合 AOP&#xff08;面向切面编程&#xff09; 和 异步方法&#xff08;Async&#xff09;&#xff0c;实现 动态调整线程池线程数 的能力&#xff0c;能够提升系统应对不同业务场景下异步任务处理的灵活性和稳定性。 下面是完整的实现思路…

进军场景智能体,云迹机器人又快了一步

&#xff08;图片来源&#xff1a;Pixels&#xff09; 2025年&#xff0c;AI和机器人行业都发生了巨大改变。 数科星球原创 作者丨苑晶 编辑丨大兔 2025年&#xff0c;酒店行业正掀起一股批量采购具备AI功能的软硬一体解决方案的热潮。 在DeepSeek、Manus等国产AI软件的推动…

比较Linux的Shell的 `EOF` 与 `echo` 与 `printf` , 将文本输出到文件

比较Linux的Shell的 EOF 与 echo 与 printf , 将文本输出到文件 TempVar"支持变量文本替换"# 不带-e的echo默认不执行${变量}替换 echo 第一行第二行 TempVar${TempVar}第三行 \n有没有换行? > echo1.txtecho "第一行第二行 TempVar${TempVar}第三行…