力扣日记3.8-【回溯算法篇】37. 解数独

news2025/1/16 14:00:05

力扣日记:【回溯算法篇】37. 解数独

日期:2023.3.8
参考:代码随想录、力扣

37. 解数独

题目描述

难度:困难

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

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

  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] 是一位数字或者 ‘.’
  • 题目数据 保证 输入数独仅有一个解

题解

cpp ver
class Solution {
private:
    bool isValid(vector<vector<char>>& board, int row, int col, char c) {
        // 同一行
        for (int i = 0; i < 9; i++) {
            if (board[row][i] == c) return false;
        }
        // 同一列
        for (int i = 0; i < 9; i++) {
            if (board[i][col] == c) return false;
        }
        // 确定九宫格的位置
        int x = col / 3;    // 是商而不是余数!!!
        int y = row / 3;
        for (int j = y * 3; j < y * 3 + 3; j++) {
            for (int i = x * 3; i < x * 3 + 3; i++) {
                if (board[j][i] == c)   return false;
            }
        }
        return true;
    }
public:
    void solveSudoku(vector<vector<char>>& board) {
        backtracking(board);
    }
    // 返回值:只需要找到一个解即可,所以用bool
    // 参数:board
    bool backtracking(vector<vector<char>>& board) {
        // 在当前层递归,通过两层for循环找到当前需要填数字的位置(空格)
        for (int row = 0; row < 9; row++) {
            for (int col = 0; col < 9; col++) {
                // 找到空位置
                if (board[row][col] == '.') {
                    // 如果为空,开始填数字,此时才是所谓的for循环横向遍历
                    for (char c = '1'; c <= '9'; c++) { // 啊啊啊!这里不小心写成 < '9' 直接导致不能找到答案!!!导致最后棋盘是空的
                        // 如果有效,则处理节点并递归
                        if (isValid(board, row, col, c)) {
                            board[row][col] = c;
                            // 递归(进入下一个棋盘,从头开始找空格)
                            // 这里用if接受返回结果,如果下一层递归遍历完整个棋盘都没有空格(则返回true),这里也直接返回
                            if (backtracking(board))    return true;
                            // 否则进行回溯
                            board[row][col] = '.';
                        }
                    }
                    // 如果9个数都不行,说明之前层的递归中放的数字有问题,则返回false
                    return false;
                }
            }
        }
        // 如果在当前层递归遍历完一整个棋盘都没有空格,说明填满了,返回true
        return true;
    }
#endif
};

复杂度

时间复杂度:
空间复杂度:

思路总结

  • 本题与之前做的Q皇后,甚至组合、子集等问题,在思路上完全不一致。
    • 前面的题目,在递归时是有指明递归方向的(纵向遍历),如Q皇后中,递归参数row + 1指明递归是往下一行遍历,组合、子集问题中递归参数startindex = i + 1 也指明递归是往下一个值遍历。
    • 而本题中,进入下一层递归时,并没有指明方向,而是直接给一整个棋盘,至于如何知道当前层递归需要处理的是哪个位置,则通过最开始的两层for循环来找位置。
    • 硬要说的话,可能排列问题中,在每次递归时也是直接给一整个集合,然后在下一层递归从头开始遍历(再通过used去重)。这种思路可能有点类似。但是本题除了通过for循环找到当前位置外,还要在当前位置再去进行一层横向遍历(遍历数字1-9),所以相比前者,多了一个维度。)
  • 因此,每层递归的这两个for循环,是为了找到当前这层递归,是轮到哪一个位置放数字了。一个位置一个位置看是否已经有值了,如果是空的,才进行所谓的“横向遍历”(看1-9哪一个数字有效)。再如果找到了有效的数字,就进行处理节点和递归(又从头开始找哪一个位置放数字)。
    • 有效数字要满足三个条件:
      • 同一行不能重复
      • 同一列不能重复
      • 同一个九宫格不能重复(要先确定在哪个九宫格)
  • 至于什么时候终止,则是等最后一层递归时,发现自己遍历完棋盘上所有位置都没有空格了,就返回true表示都填满了。然后退出当前层递归,会由上一层递归捕获到其返回的true,再继续退出。因此,不需要专门的终止条件。
  • 至于回溯,则是当前层递归如果试了9个数字都不行,则说明前面层的递归所放的数字是存在问题的,则返回false退出当前层递归,再由上一层递归捕获到false后进行回溯。
  • 由于需要这个true和false来判断是否终止,因此返回值则需要一个bool值(而不是之前的void)。
    • 用bool还是void与之前树的题目类似,也是看是需要一个结果(一条边)即可,还是要多个结果(所有边)

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

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

相关文章

上位机图像处理和嵌入式模块部署(qmacvisual串口输出结果)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 前面我们谈到了图像的输入、算法的添加&#xff0c;一切看上去都没有问题。但是这中间缺少了一个重要的环节&#xff0c;那就是结果的输出。如果我…

Java中的参数传递

程序设计语言将实参传递给方法&#xff08;或函数&#xff09;的方式分为两种&#xff1a; 值传递&#xff1a;方法接收的是实参值的拷贝&#xff0c;会创建副本。引用传递&#xff1a;方法接收的直接是实参所引用的对象在堆中的地址&#xff0c;不会创建副本&#xff0c;对形…

一文掌握mysql中的查询语句

目录 1. 聚合查询1.1 聚合函数1.2 GROUP BY子句1.3 HAVING 2. 联合查询2.1 内连接2.2 外连接2.3 自连接2.4 子查询2.5 合并查询 1. 聚合查询 1.1 聚合函数 常见的统计总数、计算平局值等操作&#xff0c;可以使用聚合函数来实现&#xff0c;常见的聚合函数有&#xff1a; 函…

Ubuntu 基本操作-嵌入式 Linux 入门

在 Ubuntu 基本操作 里面基本就分为两部分&#xff1a; 安装 VMware 运行 Ubuntu熟悉 Ubuntu 的各种操作、命令 如果你对 Ubuntu 比较熟悉的话&#xff0c;安装完 VMware 运行 Ubuntu 之后就可以来学习下一章节了。 1. 安装 VMware 运行 Ubuntu 我们首先来看看怎么去安装 V…

[MYSQL数据库]--表内操作(CURD)

前言 作者&#xff1a;小蜗牛向前冲 名言&#xff1a;我可以接受失败&#xff0c;但我不能接受放弃 如果觉的博主的文章还不错的话&#xff0c;还请点赞&#xff0c;收藏&#xff0c;关注&#x1f440;支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 目录 一、表的 Cre…

【rk3368 android6.0 恢复出厂设置功能】

rk3368 android6.0 恢复出厂设置功能 恢复出厂设置三种方法一&#xff0c;设置--进入恢复出厂设置页面二&#xff0c;发送广播形式三&#xff0c;命令形式总结 郑重声明:本人原创博文&#xff0c;都是实战&#xff0c;均经过实际项目验证出货的 转载请标明出处:攻城狮2015 恢复…

视频素材网站哪个好?推荐几个高清无水印的短视频素材网

小伙伴们&#xff0c;如果你也是短视频的狂热爱好者&#xff0c;想要制作出优质满分的短视频作品&#xff0c;但苦于不知道从哪儿搞来那些高清无水印的素材&#xff0c;那今天你就来对地方啦&#xff01;我这里有几个绝佳的素材网站推荐给你&#xff0c;让你的创作源源不断。 …

Kubernetes kafka系列 | k8s部署kafka+zookeepe集群(可外部通信)| kafka docekr镜像制作-v3.5.2

一、 Kafka、ZooKeeper 的分布式消息队列系统总体架构 典型的 Kafka 体系架构包括若干 Producer(消息生产者),若干 Broker(作为 Kafka 节点的服务器),若干 Consumer (Group),以及一个 ZooKeeper 集群。 Kafka 通过 ZooKeeper 管理集群配置、选举 Leader,并在 Consum…

自动化运维工具 ---------------Ansible

一、Ansible 发展史及功能 作者&#xff1a;Michael DeHaan&#xff08; Cobbler pxe kikstar 与 Func 作者&#xff09;ansible 的名称来自科幻小说《安德的游戏》中跨越时空的即时通信工具&#xff0c;使用它可以在相距数光年的距离&#xff0c;远程实时控制前线的舰队战斗2…

AI人员睡岗识别摄像机

近年来&#xff0c;随着人工智能技术的不断发展&#xff0c;智能监控系统也得到了广泛应用。其中&#xff0c;AI人员睡岗识别摄像机作为一种新型的智能监控设备&#xff0c;正在逐渐受到企业和机构的关注和使用。这种摄像机利用人工智能技术&#xff0c;能够实时监测和识别工作…

智能指针的讲解

1.为什么要智能指针 首先我们分析一段代码&#xff1a; 1、如果p1这里new 抛异常会如何&#xff1f; 2、如果p2这里new 抛异常会如何&#xff1f; 3、如果div调用这里又会抛异常会如何&#xff1f; int div() {int a, b;cin >> a >> b;if (b 0)throw invalid_ar…

别再写传统简历了!AI简历5个超实用的功能,助你求职一臂之力(强烈建议收藏)

你们在制作简历时,是不是基本只关注两件事:简历模板,还有基本信息的填写。 当你再次坐下来更新你的简历时,可能会发现自己不自觉地选择了那个“看起来最好看的模板”,填写基本信息,却没有深入思考如何使简历更具吸引力。这其实是一个普遍现象:许多求职者仍停留在传统简历…

使用Julia语言展示几何平均值与算数平均值在实际应用中的差别(采用注册计量师考试试题)

理论部分 在注册计量师考试中有一道试题&#xff0c;大体内容为&#xff1a; 现在有一块砝码在等臂天平上进行测量&#xff0c;第一次测得值是19.6g&#xff0c;调换两边位置后的测得值是19.7g&#xff0c; 天平最终测得检测样品的重量为多少&#xff1f; 个别同事可能会将算…

每日一题leetcode -299.猜数字游戏

水一期 class Solution { public:string getHint(string secret, string guess) {int bulls 0;vector<int> cntS(10), cntG(10);for (int i 0; i < secret.length(); i) {if (secret[i] guess[i]) {bulls;} else {cntS[secret[i] - 0];cntG[guess[i] - 0];}}int c…

蓝桥杯真题讲解:三国游戏(贪心)

蓝桥杯真题讲解&#xff1a;三国游戏&#xff08;贪心&#xff09; 一、视频讲解二、正解代码 一、视频讲解 蓝桥杯真题讲解&#xff1a;三国游戏&#xff08;贪心&#xff09; 二、正解代码 //三国游戏&#xff1a;贪心 #include<bits/stdc.h> #define int long lon…

DJI RONIN 4D变0字节恢复案例

RONIN 4D这个产品听起来比较陌生&#xff0c;还是DJI大疆出品。没错&#xff0c;这是大疆进军影视级的重点明星机型。前阵子刚处理过大疆RONIN 4D的修复案例&#xff0c;下边这个案例是和exfat有关的老问题:文件长度变成0字节。 故障存储:希捷18T /MS Exfat文件系统。 故障现…

navicat查询结果导出(excle、txt、sql、html等)

执行查询结果后按照如下流程操作&#xff1a; 1、点击“文件”&#xff0c;选择“导出结果” 2、在弹出的弹窗中选择“导出当前的结果” 3、选择需要导出的格式&#xff0c;点击“下一步” 4、选择路径后&#xff0c;点击“下一步” 5、默认点击“下一步” 6、点击“开始” 7、…

计算机缺失iutils.dll怎么办,分享5种靠谱的解决方法

​在计算机系统运行过程中&#xff0c;如果发现无法找到或缺失iutils.dll文件&#xff0c;可能会引发一系列的问题与故障。首先&#xff0c;由于iutils.dll是系统中一个重要的动态链接库文件&#xff0c;它的主要功能可能涉及到系统核心服务、应用程序支持或者特定功能模块的运…

漫途桥梁结构安全监测方案,护航桥梁安全!

桥梁作为城市生命线的重要组成部分&#xff0c;承载着城市交通、物流输送、应急救援等重要职能。然而&#xff0c;随着我国社会经济的飞速发展&#xff0c;桥梁所承载的交通流量逐年增长&#xff0c;其安全性所面临的挑战亦日益严峻。例如恶劣的外部环境、沉重的荷载以及长期使…

C语言例2-1:从键盘输入两个整数,计算其乘积

代码如下&#xff1a; //从键盘输入两个整数&#xff0c;计算其乘积 #include<stdio.h> int main(void) /*主函数*/ {int n1, n2, result; /*定义保存两个整数及其乘积的变量*/printf("please inp…