leetcode 37. 解数独 思考分析

目录

    • 题目
    • 核心思路的不断细化
      • 1、核心框架
      • 2、考虑到每个位置的工作
      • 3、考虑到到达最后一列、该位置的数已经预置的情况
      • 4、判断是否符合规则的函数
      • 5、确定递归终止条件+确定函数返回值
    • AC代码

题目

编写一个程序,通过填充空格来解决数独问题。
一个数独的解法需遵循如下规则:

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

空白格用 ‘.’ 表示。

一个数独。
答案被标成红色。
提示:

给定的数独序列只包含数字 1-9 和字符 ‘.’ 。
你可以假设给定的数独只有唯一解。
给定数独永远是 9x9 形式的。

核心思路的不断细化

算法的核心思路就是对每一个空着的格子穷举 1 到 9,如果遇到不合法的数字(在同一行或同一列或同一个 3×3 的区域中存在相同的数字)则跳过,如果找到一个合法的数字,则继续穷举下一个空格子。
写出核心框架:

1、核心框架

void solveSudoku(vector<vector<char>>& board) {backtrack(board, 0, 0);
}void backtrack(vector<vector<char>>& board, int hang, int lie) {// 就是对棋盘的每个位置进行穷举for (int i = hang; i < 9; i++) {for (int j = lie; j < 9; j++) {// 做选择backtrack(board, i, j);// 撤销选择}}
}

2、考虑到每个位置的工作

对于每个位置有1~9的选择,这样就变成了3重嵌套循环。

void backtrack(vector<vector<char>>& board, int hang, int lie) {// 就是对每个位置进行穷举for (int i = hang; i < 9; i++) {for (int j = lie; j < 9; j++) {for (char ch = '1'; ch <= '9'; ch++) {// 做选择board[i][j] = ch;// 继续穷举下一列,backtrack(board, i, j + 1);// 撤销选择board[i][j] = '.';}}}
}

3、考虑到到达最后一列、该位置的数已经预置的情况

1、当lie到达超过最后一个索引时,转为增加hang开始穷举下一行。
2、如果当前位置元素不为“.”,那么跳过即可。
3、穷举的时候如果遇到符合规则的数字,填入,否则跳过。

void backtrack(vector<vector<char>>& board, int hang, int lie) {if(lie==9){backtrack(board, hang+1, 0);}// 就是对每个位置进行穷举for (int i = hang; i < 9; i++) {for (int j = lie; j < 9; j++) {// 如果该位置是预设的数字,不用我们操心if (board[i][j] != '.') {backtrack(board, i, j + 1);return;} //如果不是预置的数字for (char ch = '1'; ch <= '9'; ch++) {// 如果遇到符合规则的数字,填入if (isValid(board, i, j, ch)){// 做选择board[i][j] = ch;// 继续穷举下一列,backtrack(board, i, j + 1);// 撤销选择board[i][j] = '.';}}}}
}

4、判断是否符合规则的函数

规则如下:

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

翻译成函数:
注意这里对第3个规则的描述:

// 判断 board[i][j] 是否可以填入 n
bool isValid(vector<vector<char>>& board, int hang, int lie, char n) {for (int i = 0; i < 9; i++) {// 判断行是否存在重复if (board[hang][i] == n) return false;// 判断列是否存在重复if (board[i][lie] == n) return false;// 判断 3 x 3 方框是否存在重复if (board[(hang/3)*3 + i/3][(lie/3)*3 + i%3] == n)return false;}return true;
}

下面是这个式子的含义,并且将i=0~8模拟了一下:
在这里插入图片描述

5、确定递归终止条件+确定函数返回值

如果递归完最后一行,那么我们就可以返回我们的结果了。
如果找到一个解我们的任务就结束了,本题并没有要求找到所有解。
如果一个位置遍历完所有数字,都不符合,这说明此路不通,应该及时返回false。
如果每个位置都遍历过了,结果都没有返回true,说明,这个数独棋盘没有解,返回false。
所以使用bool类型的值作为返回值:

if(hang == 9) return true;

完整的回溯函数代码应该如下:

bool backtrack(vector<vector<char>>& board, int hang, int lie) {//遍历完这一行最后一列,转而遍历下一行if(lie==9){return backtrack(board, hang+1, 0);}//找到一个解,返回if(hang == 9) return true;// 就是对每个位置进行穷举for (int i = hang; i < 9; i++) {for (int j = lie; j < 9; j++) {// 如果该位置是预设的数字,不用我们操心if (board[i][j] != '.') {return backtrack(board, i, j + 1);} //如果不是预置的数字for (char ch = '1'; ch <= '9'; ch++) {// 如果遇到符合规则的数字,填入if (isValid(board, i, j, ch)){// 做选择board[i][j] = ch;// 继续穷举下一列,如果找到了一个解,立即结束if(backtrack(board, i, j + 1) == true) return true;// 撤销选择board[i][j] = '.';}}// 穷举完 1~9,依然没有找到可行解,此路不通return false;}}return false;
}

AC代码

class Solution {
public:// 判断 board[i][j] 是否可以填入 nbool isValid(vector<vector<char>>& board, int hang, int lie, char n) {for (int i = 0; i < 9; i++) {// 判断行是否存在重复if (board[hang][i] == n) return false;// 判断列是否存在重复if (board[i][lie] == n) return false;// 判断 3 x 3 方框是否存在重复if (board[(hang/3)*3 + i/3][(lie/3)*3 + i%3] == n)return false;}return true;}bool backtrack(vector<vector<char>>& board, int hang, int lie) {//遍历完这一行最后一列,转而遍历下一行if(lie==9){return backtrack(board, hang+1, 0);}//找到一个解,返回if(hang == 9) return true;// 就是对每个位置进行穷举for (int i = hang; i < 9; i++) {for (int j = lie; j < 9; j++) {// 如果该位置是预设的数字,不用我们操心if (board[i][j] != '.') {return backtrack(board, i, j + 1);} //如果不是预置的数字for (char ch = '1'; ch <= '9'; ch++) {// 如果遇到符合规则的数字,填入if (isValid(board, i, j, ch)){// 做选择board[i][j] = ch;// 继续穷举下一列,如果找到了一个解,立即结束if(backtrack(board, i, j + 1) == true) return true;// 撤销选择board[i][j] = '.';}}// 穷举完 1~9,依然没有找到可行解,此路不通return false;}}return false;}void solveSudoku(vector<vector<char>>& board) {backtrack(board, 0, 0);return;}
};

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

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

相关文章

快速完成兼职外包开发任务

做了很多年的开发相关的工作&#xff0c;做过兼职开发&#xff0c;也做过外包一些开发项目。 兼职人员角色时 正是经历这些事情时&#xff0c;每次就要提前很费经的跟公司沟通&#xff0c;让他们把公司内部的svn开发出去&#xff0c;但是就是很难&#xff0c;会涉及到安全各方的…

使用YOLOv5训练NEU-DET数据集

一、下载YOLOv5源码和NEU-DET(钢材表面缺陷)数据集 YOLOv5源码 NEU-DET(钢材表面缺陷)数据集 这里的数据集已经经过处理了&#xff0c;下载即可 若通过其他途径下载的原始数据集标签为xml格式&#xff0c;需要转化为txt格式XML转txt格式脚本 二、数据集准备 NEU-DET(钢材表…

带分页功能的SSH整合,DAO层经典封装

任何一个封装讲究的是&#xff0c;使用&#xff0c;多状态。Action&#xff1a;任何一个Action继承分页有关参数类PageManage&#xff0c;自然考虑的到分页效果&#xff0c;我们必须定义下几个分页的参数。并根据这个参数进行查值。然后在继承ServiceManage&#xff0c;Service…

leetcode 198. 打家劫舍 思考分析

目录1、题目2、求解思路3、代码1、题目 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&#xff0c;如果两间相邻的房屋在同一晚上被小偷闯入&#xff0c;系统会自动…

找不到Windows照片查看器解决方法

桌面创建一个txt文本 复制这些命令&#xff0c;之后将后缀改为.reg&#xff0c;右击管理员身份运行即可 Windows Registry Editor Version 5.00 ; Change Extensions File Type [HKEY_CURRENT_USER\Software\Classes\.jpg] "PhotoViewer.FileAssoc.Tiff" ; Change E…

伙伴分配器的一个极简实现

提起buddy system相信很多人不会陌生&#xff0c;它是一种经典的内存分配算法&#xff0c;大名鼎鼎的Linux底层的内存管理用的就是它。这里不探讨内核这么复杂实现&#xff0c;而仅仅是将该算法抽象提取出来&#xff0c;同时给出一份及其简洁的源码实现&#xff0c;以便定制扩展…

[USACO3.2.3 Spinning Wheels]

[关键字]&#xff1a;模拟 枚举 [题目大意]&#xff1a;有5个轮子&#xff0c;每个轮子优r个缺口并且会按一定速度不停转动&#xff0c;问什么时候可以使一条光线射过所有轮子。 // [分析]&#xff1a;从0到1000&#xff08;或其他的&#xff09;枚举分钟然后判断&#xff0c;当…

一、SQLServer2008安装(带密码)、创建数据库、C#窗体项目测试

一、下载和安装SQLServer2008 东西太大了&#xff0c;没法上传到资源里面&#xff0c;官网其他公众号都下载可以。 右击管理员身份 运行setup.exe 这个密钥不能用的话&#xff0c;也可以去百度其他密钥 JD8Y6-HQG69-P9H84-XDTPG-34MBB 建议改一下路径&#xff0c;我这边修…

【C++grammar】多态、联编、虚函数

目录1、多态概念1.多态性有两种表现的方式2、联编&#xff08;实现多态&#xff09;1.静态联编2.动态联编3、实现运行时多态1.为何要使用运行时多态&#xff1f;2.如何实现运行时多态3.多态的例子1.调用哪个同名虚函数&#xff1f;2. 用途&#xff1a;可以用父类指针访问子类对…

一 MVC - HtmlHelper

HtmlHelper类位于System.Web.Mvc.Html之中主要有七个静态类组成&#xff1a; FormExtensions - BeginForm, BeginRouteForm, EndForm InputExtensions - CheckBox, CheckBoxFor, Hidden, HiddenFor, Password, PasswordFor, RadioButton, RadioButtonFor, TextBox, TextBoxFor …

二、用户登录和注册

一、页面设计 一共四个页面 主页面Form1&#xff0c;登录页面login&#xff0c;注册页面resister&#xff0c;主菜单页面main_page 系统运行进入Form1&#xff0c;单击登录按钮跳转到login&#xff0c;数据库中得存在数据信息且输入正确才可登录成功&#xff0c;跳转到main_pa…

【C++grammar】访问控制与抽象类与纯虚函数

目录一、访问控制 (可见性控制)1.private、public、protected关键字2.关键字示例1、关键字对类数据成员访问的限制3. 公有继承4. 私有继承5. 保护继承6. 私有继承和保护继承的区别二、抽象类与纯虚函数1.什么是抽象类2.抽象函数/纯虚函数3.抽象类示例一、访问控制 (可见性控制)…

三、上传织物图片至SQL Server并提供name进行展示织物照片

一、数据库的建立 还是在fiber_yy数据库下创建images表 images表设计如下 二、页面完善设计 main_page页面进行功能完善 入库管理系统 warehousing页面 库存查询系统 query页面 登录注册页面前面几个博文已经实现过了&#xff0c;这里就再赘述了&#xff0c;仍是沿用前…

ARM MMU工作原理剖析[转]

一、MMU的产生 许多年以前&#xff0c;当人们还在使用DOS或是更古老的操作系统的时候&#xff0c;计算机的内存还非常小&#xff0c;一般都是以K为单位进行计算&#xff0c;相应的&#xff0c;当时的程序规模也不大&#xff0c;所以内存容量虽然小&#xff0c;但还是可以容纳当…

【原创】SharePoint Document library List Check out 文档时碰到的问题解决

环境&#xff1a;TFS(Team Foundation Server)集成的WSS 3.0&#xff08;SharePoint Service 3.0&#xff09; 问题&#xff1a;如题&#xff0c;祥见下图 解决&#xff1a;一般碰到没有经验的问题&#xff0c;大家当然是外事不决问谷歌了&#xff0c;于是谷歌搜到了这篇博客 h…

四、入库管理功能的完善

一、数据库的创建 在fiber_yy数据库下创建yy_textile表 先随便添加几条数据 二、页面的完善 登录注册页面我就不演示了&#xff0c;前几篇博文也都有介绍 warehousing入库页面 main_page页面进行功能完善 三、代码实现 warehousing页面 using System; using System.…

leetcode 232. 用栈实现队列 思考分析

题目 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列的支持的所有操作&#xff08;push、pop、peek、empty&#xff09;&#xff1a; 实现 MyQueue 类&#xff1a; void push(int x) 将元素 x 推到队列的末尾 int pop() 从队列的开头移除并返回元素 int peek() 返…

YCSB初步介绍

随着大数据时代的到来和云计算的不断发展&#xff0c;作为云计算最基础的设施存储产品也越来越多&#xff0c;开源分布式存储系统有BigTable-like系统HBase&#xff0c;dynamo-like系统Cassandra&#xff0c;voldemort&#xff0c;Riak&#xff0c;淘宝开源的OceanBase等。当然…

【C++grammar】动态类型转换、typeid与RTTI

目录动态类型转换1、为何需要动态类型转换2、dynamic_cast<>();运算符3、向上转换和向下转换( Upcasting and Downcasting)4、 基类对象和派生类对象的互操作5、Upcasting/Downcasting与继承链上不同类的对象之间的赋值有什么关系和区别&#xff1f;typeid 运行时查询类型…

五、库存查询功能的完善

一、数据库的建立 由于查询功能和之前的 入库管理功能 所用的数据库都一样&#xff0c;这里仍使用yy_textile表 在fiber_yy数据库下创建yy_textile表 初始数据库信息 二、页面的完善 登录注册页面我就不演示了&#xff0c;前几篇博文也都有介绍 query查询页面 main_page…