【回溯 状态压缩 深度优先】37. 解数独

本文涉及知识点

回溯 状态压缩 深度优先

LeetCode37. 解数独

编写一个程序,通过填充空格来解决数独问题。
数独的解法需 遵循如下规则:
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)
数独部分空格内已填入了数字,空白格用 ‘.’ 表示。

示例 1:
输入:board = [[“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”]]
解释:输入的数独如上图所示,唯一有效的解决方案如下所示:
提示:
在这里插入图片描述

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

回溯

vRow[i] 记录第i行可以选择那些数,vCol[i]和vCell类型。
vRow[i] & ( 1 << j) 表示第i行,可以选择数组j。
直接将选择结果修改到board上。
vector<tuple<int,int,int>> vSel。 i1,记录可以选择的数量,i2记录行号,i3记录列号。注意:只需要记录能修改的数组。 初始化结束后,对vSel排序。理论上:只有一种选择的先选快点。实际上几乎无影响。
用深度优先实现。Fill 函数填写某行某列,UnFill 恢复某行某列原装。
时间复杂度:不好计算。

代码

核心代码

class CBitCounts
{
public:CBitCounts(int iMaskCount){for (int i = 0; i < iMaskCount; i++){m_vCnt.emplace_back(bitcount(i));}}template<class T>static int bitcount(T x) {int countx = 0;while (x) {countx++;x &= (x - 1);}return countx;}vector<int> m_vCnt;
};class Solution {
public:void solveSudoku(vector<vector<char>>& board) {m_board = board;int mask = 0;for (int i = 1; i <= 9; i++) {mask |= (1 << i);}for (int i = 0; i < 9; i++) {m_rows[i] = m_cols[i] = m_cells[i] = mask;}for (int r = 0; r < 9; r++) {for (int c = 0; c < 9; c++) {if ('.' == board[r][c]) { continue; }Fill(r, c, board[r][c] - '0');}}vector<tuple<int, int, int,int>> vSel;for (int r = 0; r < 9; r++) {for (int c = 0; c < 9; c++) {if ('.' != board[r][c]) { continue; }int iCell = r / 3 * 3 + c / 3;int mask = m_rows[r] & m_cols[c] & m_cells[iCell];vSel.emplace_back(CBitCounts::bitcount(mask), r, c,iCell);}}sort(vSel.begin(), vSel.end());DFS(vSel, 0);board = m_board;}bool DFS(const vector<tuple<int, int, int,int>> vSel, int leve) {if (vSel.size() == leve) { return true; }const auto& [tmp, r, c, iCell] = vSel[leve];int mask = m_rows[r] & m_cols[c] & m_cells[iCell];for (int i = 1; i <= 9; i++) {if (mask & (1 << i)) {Fill(r, c, i);if (DFS(vSel, leve + 1)) { return true; }UnFill(r, c, i);}}return false;}void Fill (int r, int c, int val) {m_board[r][c] = val + '0';m_rows[r] &= ~(1 << val);m_cols[c] &= ~(1 << val);int iCell = r / 3 * 3 + c / 3;m_cells[iCell] &= ~(1 << val);};void UnFill(int r, int c, int val) {m_board[r][c] = '.';m_rows[r] |= (1 << val);m_cols[c] |= (1 << val);int iCell = r / 3 * 3 + c / 3;m_cells[iCell] |= (1 << val);};vector<vector<char>> m_board;int m_rows[9], m_cols[9], m_cells[9];
};

测试用例

template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{if (v1.size() != v2.size()){assert(false);return;}for (int i = 0; i < v1.size(); i++){assert(v1[i] == v2[i]);}
}template<class T>
void Assert(const T& t1, const T& t2)
{assert(t1 == t2);
}int main()
{vector<vector<char>> board;{Solution slu;board ={ {'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' }};slu.solveSudoku(board);vector<vector<char>> board1={ {'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' }};Assert(board1, board);}	
}

2023年5月代码

记录已经选择的数,这样初始化简单。用二维数组记录3 × \times × 3 网格的情况,减少计算网格号。

class Solution {
public:void solveSudoku(vector<vector<char>>& board) {memset(m_aRows, 0, sizeof(m_aRows));memset(m_aCols, 0, sizeof(m_aCols));memset(m_aBlock, 0, sizeof(m_aBlock));for (int r = 0; r < 9; r++){for (int c = 0; c < 9; c++){const char& ch = board[r][c];if ('.' == ch){m_vNeedDoRowCols.emplace_back(r, c);continue;}Add(r, c, ch - '1');}}dfs(board, 0);}bool dfs(vector<vector<char>>& board,int iLeve){if (m_vNeedDoRowCols.size() == iLeve){return true;}const int r = m_vNeedDoRowCols[iLeve].first;const int c = m_vNeedDoRowCols[iLeve].second;int iMask = m_aRows[r] | m_aCols[c] | m_aBlock[r/3][c/3];for (int i = 0; i < 9; i++){if (iMask & (1 << i)){continue;}Add(r, c, i);board[r][c] = '1' + i;if (dfs(board, iLeve + 1)){return true;}board[r][c] = '.';Erase(r, c, i);}return false;}void Add(int r, int c, int iNum){const int iMask = 1 << iNum;m_aRows[r] |= iMask;m_aCols[c] |= iMask;m_aBlock[r / 3][c / 3] |= iMask;}void Erase(int r, int c, int iNum){const int iMask = 1 << iNum;m_aRows[r] -= iMask;m_aCols[c] -= iMask;m_aBlock[r / 3][c / 3] -= iMask;}int m_aRows[9],m_aCols[9];int m_aBlock[3][3];vector<std::pair<int, int>> m_vNeedDoRowCols;
};

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

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

相关文章

[C++核心编程-06]----C++类和对象之对象模型和this指针

&#x1f3a9; 欢迎来到技术探索的奇幻世界&#x1f468;‍&#x1f4bb; &#x1f4dc; 个人主页&#xff1a;一伦明悦-CSDN博客 ✍&#x1f3fb; 作者简介&#xff1a; C软件开发、Python机器学习爱好者 &#x1f5e3;️ 互动与支持&#xff1a;&#x1f4ac;评论 &…

Microsoft 365 for Mac v16.84 office365全套办公软件

Microsoft 365 for Mac是一款功能丰富的办公软件套件&#xff0c;为Mac用户提供了丰富的功能和工具&#xff0c;提高了工作效率和协作能力。Microsoft 365 for Mac是一款专为Mac用户设计的订阅式办公软件套件&#xff0c;旨在提高生产力和效率。 Microsoft 365 for Mac v16.84正…

ubantu安装docker以及docker-compose

ubantu安装docker以及docker-compose 安装docker1、从官方存储库中安装Docker2、启动Docker服务3、验证 安装docker compose使用docker部署服务1、需要再opt文件夹下创建以下文件夹&#xff0c;/opt文件夹目录说明2、可将已备份对应文件夹拷至对应文件夹下3、在/opt/compose目录…

霍金《时间简史 A Brief History of Time》书后索引(A--D)

图源&#xff1a;Wikipedia INDEX A Abacus Absolute position Absolute time Absolute zero Acceleration Age of the universe Air resistance Albrecht, Andreas Alpha Centauri Alpher, Ralph Anthropic principle Antigravity Antiparticles Aristotle Arrows of time …

基于Vant UI的微信小程序开发(随时更新的写手)

基于Vant UI的微信小程序开发✨ &#xff08;一&#xff09;悬浮浮动1、效果图&#xff1a;只要无脑引用样式就可以了2、页面代码3、js代码4、样式代码 &#xff08;二&#xff09;底部跳转1、效果图&#xff1a;点击我要发布跳转到发布的页面2、js代码3、页面代码4、app.json代…

我觉得POC应该贴近实际

今天我看到一位老师给我一份测试数据。 这是三个国产数据库。算是分布式的。其中有两个和我比较熟悉&#xff0c;但是这个数据看上去并不好。看上去第一个黄色的数据库数据是这里最好的了。但是即使如此&#xff0c;我相信大部分做数据库的人都知道。MySQL和PostgreSQL平时拿出…

Spark Streaming笔记总结(保姆级)

万字长文警告&#xff01;&#xff01;&#xff01; 目录 一、离线计算与流式计算 1.1 离线计算 1.1.1 离线计算的特点 1.1.2 离线计算的应用场景 1.1.3 离线计算代表技术 1.2 流式计算 1.2.1 流式计算的特点 1.2.2 流式计算的应用场景 1.2.3 流式计算的代表技术 二…

kernel32.dll丢失要如何解决?电脑kernel32.dll文件下载方法

kernel32.dll丢失要怎么解决才好&#xff1f;其实针对这个问题还是有很多种的解决方法的&#xff0c;只要你明白了kernel32.dll的作用&#xff0c;了解kernel32.dll&#xff0c;那么就可以有很多种方法去解决&#xff0c;下面一起来看看吧。 一.了解kernel32.dll文件 kernel32…

6个超TM好用的神仙App推荐!

1. AI文本视频生成工具——Jurilu Jurilu 是一款功能强大的 AI 文本视频生成器&#xff0c;允许用户快速将文本内容转换成极具吸引力的视频。它的使用非常简单&#xff1a;只需要输入文字&#xff0c;选择想要的样式和模板&#xff0c;Jurilu 就会自动将文字转换成生动的视频。…

Vue项目npm install certificate has expired报错解决方法

1.Vue项目 npm install 安装依赖突然报错&#xff1a; npm ERR! code CERT_HAS_EXPIRED npm ERR! errno CERT_HAS_EXPIRED npm ERR! request to https://registry.npm.taobao.org/zrender/download/zrender-4.3.0.tgz failed, reason: certificate has expired npm ERR! A com…

一个可以同时使用USB和WIFI传输文件到电脑的软件

双轨快传 结合USB2.0和WIFI6技术&#xff0c;通过1000Mbps网口实现每秒高达150MB的传输速率&#xff08;理论上可达40MB/s通过USB和110MB/s通过WIFI&#xff09;。 使用 模式 支持普通模式和Root模式&#xff0c;Root模式可访问~/Android/data/与/data/data/目录下的文件。 …

ETL-kettle数据转换及组件使用详解

目录 一、txt文本转换成excel 1、新建、转换 2、构建流程图 3、配置数据流图中的各个组件 3.1、配置文件文本输入组件 3.2、 配置Excel输出组件 4、保存执行 二、excel转换成mysql &#xff08;1&#xff09;在MySQL数据库中创建数据库&#xff0c;这个根据自身情况。我…

一文了解spring的aop知识

推荐工具 objectlog 对于重要的一些数据&#xff0c;我们需要记录一条记录的所有版本变化过程&#xff0c;做到持续追踪&#xff0c;为后续问题追踪提供思路。objectlog工具是一个记录单个对象属性变化的日志工具,工具采用spring切面和mybatis拦截器相关技术编写了api依赖包&a…

机器学习实战宝典:用scikit-learn打造智能应用

书接上文——《数据探险家的终极指南&#xff1a;用Python挖掘机器学习的奥秘》 前文我们在这段精彩的机器学习探险之旅中&#xff0c;从基础概念出发&#xff0c;深入探索了使用Python和scikit-learn库进行数据分析和模型构建的全过程。 我们首先了解了机器学习的基本原理&am…

Mysql 锁

锁 从锁的性能有乐观锁和悲观锁&#xff1b;锁的粒度有行锁、页锁、表锁&#xff1b;锁的对数据库操作类型有读锁、写锁、意向锁 乐观锁&#xff1a;采用cas机制&#xff0c;不会阻塞数据库操作&#xff0c;只会针对当前事务进行失败重试。(用于写操作不多的情况)悲观锁&…

[c++]多态的分析

多态详细解读 多态的概念多态的构成条件 接口继承和实现继承: 多态的原理:动态绑定和静态绑定 多继承中的虚函数表 多态的概念 -通俗的来说&#xff1a;当不同的对象去完成某同一行为时&#xff0c;会产生不同的状态。 多态的构成条件 必须通过基类的指针或者引用调用虚函数1虚…

C语言/数据结构——(链表的回文结构)

一.前言 今天在牛客网上刷到了一道链表题——链表的回文结构https://www.nowcoder.com/practice/d281619e4b3e4a60a2cc66ea32855bfa?&#xff0c;巧合的是它的解题思路恰好是我们一起分享过两道链表题的汇总。这两道题分别是反转链表和链表的中间节点。废话不多数&#xff0c…

Redis 源码安装和入门介绍

Linux下的redis源码安装 redis介绍 Redis 是一个开源&#xff08;BSD许可&#xff09;的&#xff0c;内存中的数据结构存储系统&#xff0c;它可以用作数据库、缓存和消息中间件。它支持多种类型的数据结构&#xff0c;如 字符串&#xff08;strings&#xff09;&#xff0c;…

智能商品计划系统:引领未来零售业的革新之路

随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;和大数据技术已成为推动各行业革新的关键动力。在零售行业中&#xff0c;智能商品计划系统的出现&#xff0c;正逐步改变着传统的商品规划与管理方式&#xff0c;为品牌注入新的活力与竞争力。本文将对智能商…

Java入门基础学习笔记14——数据类型转换

类型转换&#xff1a; 1、存在某种类型的变量赋值给另一种类型的变量&#xff1b; 2、存在不同类型的数据一起运算。 自动类型转换&#xff1a; 类型范围小的变量&#xff0c;可以直接赋值给类型范围大的变量。 byte类型赋值给int类型&#xff0c;就是自动类型转换。 pack…