解数独--难的一批

news2024/11/25 6:57:12

1题目

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

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

  1. 数字 1-9 在每一行只能出现一次。
  2. 数字 1-9 在每一列只能出现一次。
  3. 数字 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] 是一位数字或者 '.'
  • 题目数据 保证 输入数独仅有一个解

2链接

题目链接:37. 解数独 - 力扣(LeetCode)

视频链接:回溯算法二维递归?解数独不过如此!| LeetCode:37. 解数独_哔哩哔哩_bilibili

3解题思路

本题与N皇后问题不同的是,递归维度又高了一层。以前都是一维递归,本题是二维递归

N皇后问题 (opens new window)是因为每一行每一列只放一个皇后,只需要一层for循环遍历一行,递归来遍历列,然后一行一列确定皇后的唯一位置。

本题就不一样了,本题中棋盘的每一个位置都要放一个数字(而N皇后是一行只放一个皇后),并检查数字是否合法,解数独的树形结构要比N皇后更宽更深

因为这个树形结构太大,抽取一部分,如图所示:

回溯三部曲

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

递归函数的返回值需要是bool类型,为什么呢?

因为解数独找到一个符合的条件(就在树的叶子节点上)立刻就返回,相当于找从根节点到叶子节点一条唯一路径,所以需要使用bool返回值。

bool backtracking(vector<vector<char>>& board)

2、确定递归终止条件

本题递归不用终止条件,解数独是要遍历整个树形结构寻找可能的叶子节点就立刻返回。

不用终止条件会不会死循环?

递归的下一层的棋盘一定比上一层的棋盘多一个数,等数填满了棋盘自然就终止(填满当然好了,说明找到结果了),所以不需要终止条件!

那么有没有永远填不满的情况呢?

这个问题在递归单层搜索逻辑里再来讲!

3、单层递归逻辑

在树形图中可以看出我们需要的是一个二维的递归(也就是两个for循环嵌套着递归)

一个for循环遍历棋盘的行,一个for循环遍历棋盘的列,一行一列确定下来之后,递归遍历这个位置放9个数字的可能性!

bool backtracking(vector<vector<char>>& board) {
    for (int i = 0; i < board.size(); i++) {        // 遍历行
        for (int j = 0; j < board[0].size(); j++) { // 遍历列
            if (board[i][j] != '.') continue;
            for (char k = '1'; k <= '9'; k++) {     // (i, j) 这个位置放k是否合适
                if (isValid(i, j, k, board)) {
                    board[i][j] = k;                // 放置k
                    if (backtracking(board)) return true; // 如果找到合适一组立刻返回
                    board[i][j] = '.';              // 回溯,撤销k
                }
            }
            return false;                           // 9个数都试完了,都不行,那么就返回false
        }
    }
    return true; // 遍历完没有返回false,说明找到了合适棋盘位置了
}

注意:if (backtracking(board)) return true; // 如果找到合适一组立刻返回。然后就不会再撤销填进去的数字k了,这样就保证了合法的数字k留在了棋盘之中。

注意这里return false的地方,这里放return false 是有讲究的

因为如果一行一列确定下来了,这里尝试了9个数都不行,说明这个棋盘找不到解决数独问题的解!

那么会直接返回, 这也就是为什么没有终止条件也不会永远填不满棋盘而无限递归下去!

4、递归三部曲外番--判断棋盘合法性

判断棋盘是否合法有如下三个维度:

  • 同行是否重复
  • 同列是否重复
  • 9宫格里是否重复
bool isValid(int row, int col, char val, vector<vector<char>>& board) {
    for (int i = 0; i < 9; i++) { // 判断行里是否重复
        if (board[row][i] == val) {
            return false;
        }
    }
    for (int j = 0; j < 9; j++) { // 判断列里是否重复
        if (board[j][col] == val) {
            return false;
        }
    }
    int startRow = (row / 3) * 3;
    int startCol = (col / 3) * 3;
    for (int i = startRow; i < startRow + 3; i++) { // 判断9方格里是否重复
        for (int j = startCol; j < startCol + 3; j++) {
            if (board[i][j] == val ) {
                return false;
            }
        }
    }
    return true;
}

4代码

class Solution {
private:
    bool isvalid(int row, int col, char val, vector<vector<char>>& board) {
        for (int i = 0; i < 9; i++) { //判断当前行是否重复
            if (board[row][i] == val) return false;
        }
        for (int j = 0; j < 9; j++) { //判断当前列是否重复
            if (board[j][col] == val) return false;
        }
        int startRow = (row / 3) * 3; //通过去余的方式,重定位每个小九宫格的起始位置
        int startCol = (col / 3) * 3;
        for (int i = startRow; i < startRow + 3; i++) {// 判断9方格里是否重复
            for (int j = startCol; j < startCol + 3; j++) {
                if (board[i][j] == val) return false;
            }
        }
        return true;
    }

    bool backtracking(vector<vector<char>>& board) {
        for (int i = 0; i < board.size(); i++) { // 遍历行
            for (int j = 0; j < board[0].size(); j++) { // 遍历列
                if (board[i][j] == '.') { //遇到空格才继续往下判断是否可行
                    for (char k = '1'; k <= '9'; k++) { // (i, j) 这个位置放k是否合适
                        if (isvalid(i, j, k, board)) { 
                            board[i][j] = k; //放置k
                            if (backtracking(board)) return true; // 如果找到合适一组立刻返回
                            board[i][j] = '.'; //回溯撤销k
                        }                        
                    }
                    return false; //九个数字都实验完了,均找不到一组解
                }
            }
        }
        return true; // 遍历完没有返回false,说明找到了合适棋盘位置了
    }
public:
    void solveSudoku(vector<vector<char>>& board) {
        backtracking(board);
    }
};

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

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

相关文章

【MySQL】数据库SQL语句之DML

目录 前言&#xff1a; 一.DML添加数据 1.1给指定字段添加数据 1.2给全部字段添加数据 1.3批量添加数据 二.DML修改数据 三.DML删除数据 四.结尾 前言&#xff1a; 时隔一周&#xff0c;啊苏今天来更新啦&#xff0c;简单说说这周在做些什么吧&#xff0c;上课、看书、…

ubuntu编译安装pcl

环境配置&#xff1a; ubuntu18.04pcl1.11.0 下载源码并解压 tar -zxvf pcl-pcl-1.11.0.tar.gz 进入解压后的文件夹、建立bulid文件夹并进入该文件夹 安装依赖 sudo apt-get update 使用apt-get包管理器安装CMake&#xff1a; sudo apt-get install cmake 使用apt-get包管理…

创新案例 | 新锐品牌Usmile如何借助社媒运营打造爆品成为国产电动牙刷TOP1?

Usmile 是广州星际悦动股份有限公司旗下全面口腔护理品牌。2016 年至今&#xff0c;Usmile共荣获了 16 项国内外设计大奖&#xff0c;2020 年“双十一”期间&#xff0c;入选 2020 年度天猫十大新品牌&#xff0c;销售额超 1 亿&#xff0c;成为国内首个破亿的电动牙刷品牌&…

【立体视觉(一)】之成像原理与相机畸变

【立体视觉&#xff08;一&#xff09;】之成像原理与相机畸变 一、成像原理一&#xff09;针孔模型二&#xff09;坐标系转换1. 世界坐标系到相机坐标系2. 相机坐标系到图像坐标系3. 图像坐标系到像素坐标系4. 相机坐标系到像素坐标系5. 世界坐标系到像素坐标系 二、相机畸变一…

618数码节该如何挑选,推荐几款618值得入手的数码好物

又到了一年一度的618剁手季&#xff0c;各大电商平台都纷纷推出了超级大促活动&#xff0c;激发了无数值友的狂热购物欲望。你是否也已经开始摩拳擦掌&#xff0c;准备掏钱包买买买呢&#xff1f;那么赶快听听小编的建议吧&#xff01;经过自己使用的亲身体验&#xff0c;小编给…

Superset | 地图无法显示的问题

知识目录 一、写在前面二、Superset地图显示不了三、Superset无法加载已更新的MySQL数据库数据 一、写在前面 大家好&#xff01;我是初心&#xff0c;一直在寻找并尝试着适合自己的方向&#xff01; Apache Superset是一款由Python语言为主开发的开源时髦数据探索分析以及可…

高通 Camera HAL3:集成camxoverridesettings.txt到整机版本

camxoverridesettings.txt 是高通提供给开发者临时进行CAMX、CHI-CDK功能调试的一种方式&#xff0c;通过配置各种变量值然后写入到该文件&#xff0c;能控制Log打印、参数配置、数据dump等多种功能 这个文件需要集成在设备目录的vendor/etc/camera/里 因为camxoverridesetti…

2023年金九银十最新 Java面试必背八股文(含答案)详解

马上又逢金九银十&#xff0c;意味着很多人又面临着就职和跳槽&#xff0c;相信还有很多人对于自己就职没有很大的把我&#xff0c;今天就给大家分享我一个朋友总结的Java必问核心知识点&#xff0c;以及面试真题解答。 Java 面试 现在 Java 面试都是靠八股文&#xff0c;所以…

SOFA Weekly|可信基础设施技术分论坛、Layotto 社区会议回顾与预告、社区本周贡献...

SOFA WEEKLY | 每周精选 筛选每周精华问答&#xff0c;同步开源进展 欢迎留言互动&#xff5e; SOFAStack&#xff08;Scalable Open Financial Architecture Stack&#xff09;是蚂蚁集团自主研发的金融级云原生架构&#xff0c;包含了构建金融级云原生架构所需的各个组件&am…

【可乐荐书】Python自动化办公应用大全(ChatGPT版):从零开始教编程小白一键搞定烦琐工作

本栏目将推荐一些经典的、有趣的、有启发性的书籍&#xff0c;这些书籍涵盖了各个领域&#xff0c;包括文学、历史、哲学、科学、技术等等。相信这些书籍不仅可以让你获得知识&#xff0c;还可以让你感受到阅读的乐趣和魅力。 今天给大家推荐的书籍是&#xff1a;《Python自动…

互联网最全Java面试八股文,整整1658页,带你轻松应对各种面试题

又是一年一度的秋招大热门&#xff0c;为助力广大程序员朋友 “面试造火箭”&#xff0c;小编今天给大家分享的便是这份马士兵内部的面试神技——1658页《Java面试突击核心讲》&#xff01; 注&#xff1a;这份神技是由内部十余名Java架构讲师纯手打总结的最新版面试突击文档&a…

分集与路径合并方式

本专栏包含信息论与编码的核心知识&#xff0c;按知识点组织&#xff0c;可作为教学或学习的参考。markdown版本已归档至【Github仓库&#xff1a;https://github.com/timerring/information-theory 】或者公众号【AIShareLab】回复 信息论 获取。 文章目录 分集分集的概念分集…

《C和指针》读书笔记(第十章 结构和联合)

目录 0 简介1 结构基础知识1.1 结构声明1.2 结构成员1.3 结构成员的直接访问1.4 结构成员的间接访问1.5 结构的自引用1.6 不完整的声明1.7 结构的初始化 2 结构、指针和成员2.1 访问指针2.2 访问结构2.3 访问结构成员2.4 访问嵌套的结构2.5 访问指针成员 3 结构的存储分配4 作为…

TiDB亿级数据亚秒响应查询集群部署

目录 1 集群部署1.1 环境要求1.1.1 操作系统建议配置1.1.2 服务器建议配置 1.2 环境准备1.3 安装TiUP1.3.1 什么是TiUP1.3.2 安装TiUP组件1.3.3 配置TiUP环境1.3.4 检查TiUP 工具是否安装1.3.5 安装 cluster 组件1.3.6 升级cluster组件 1.4 编辑部署文件1.4.1 常见的部署场景1.…

Go语言并发微服务分布式高可用

Go语言并发微服务分布式高可用 Go语言基础 环境安装 命令行输入go&#xff0c;当前操作系统Os环境中依赖于PATH指定的日录们去找命令(可执行文件)windows会优先搜索当前日录&#xff0c;当前日录没有才依赖PATH中指定的日录 环境变量: 操作系统运行环境中提前定义好的变量P…

FreeRTOS简单任务创建和任务删除(基于stm32F407)

1. 实验目的 使用动态方法 xTaskCreate()创建任务&#xff0c;使用vTaskDelete()函数删除任务&#xff1b;创建开始任务start_task&#xff0c;在开始任务中创建其他三个任务&#xff0c;创建task1任务实现LED0每500ms闪烁一次&#xff0c;创建task2任务实现LED1每500ms闪烁一…

Linux C简易聊天室

对于初学者而已&#xff0c;我们学习的网络编程&#xff08;如TCP,UDP编程&#xff09;&#xff0c;我们通常都是在局域网内进行通信测试&#xff0c;有时候我们或者会想&#xff0c;我们现在写的内网网络数据和外网的网络数据有什么不同&#xff0c;我们内网的数据是如何走出外…

notepadd++快捷键记录

记录下 notepadd 常用快捷键 1.搜索 普通搜索&#xff1a;Ctrl F 正则表达式搜索&#xff1a; 查找模式用 正则表达式 。如 A|B|C &#xff0c;搜索多个关键字&#xff0c; 更多正则表达式探索中。 还可以选中 选取范围内 &#xff0c;就会只在鼠标选中区域内查找。 2.区…

Visual Studio Code 1.79 发布

发布模式 - 将工作区中的特定文件和文件夹标记为只读。 在某些开发场景中&#xff0c;将工作区的某些文件夹或文件显式标记为只读会很有帮助。例如&#xff0c;如果文件夹或文件内容由不同的进程管理(例如 node_modules 由 Node.js 包管理器管理的文件夹)&#xff0c;则将它们…

E往无前 | get正确使用姿势!腾讯云大数据ES日志场景优化案例回顾

导语&#xff1a; 随着ELK方案在开源日志分析领域越来越流行&#xff0c;各种业务场景也给ELK方案带来了越来越多的挑战。本文将回顾一次真实客户案例&#xff0c;从使用姿势上&#xff0c;提供一些大集群、多日志主题场景下的集群优化思路。 一、ELK不香了&#xff1f; 我们…