Leetcode:37. 解数独(C++)

news2024/11/15 16:00:12

目录

问题描述:

实现代码与解析:

回溯:

原理思路:


问题描述:

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

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

  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"]]
解释:输入的数独如上图所示,唯一有效的解决方案如下所示:

实现代码与解析:

回溯:

class Solution {
public:
    bool backtracking(vector<vector<char>>& board)
    {
        //两层循环找位置
       for(int row=0;row<board.size();row++)
       {
           for(int col=0;col<board[0].size();col++)
           {
               //找到位置
               if(board[row][col]=='.')
               {
                    //选择1~9的数字
                    for(char i='1';i<='9';i++)
                    {
                        //判断此数是否有效
                        if(isvaild(row,col,i,board))
                        {
                            board[row][col]=i;
                            bool flag=backtracking(board);//递归
                            //这里只用寻找一个符合的结果就行,找到后直接返回
                            if(flag==true)
                            {
                                return true;
                            }
                            board[row][col]='.';//回溯
                        }                       
                    }
                    return false;//都不成立,返回false
               }              
           }          
       }
       return true;//未找到位置,说明已经填满,返回true
    }

    bool isvaild(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 i=0;i<9;i++)
        {
            if(board[i][col]==val) return false;
        }
        //9格内是否有重复
        int startrow=(row/3)*3;//起始行
        int startcol=(col/3)*3;//起始列
        for(int i=startrow;i<startrow+3;i++)
        {
            for(int j=startcol;j<startcol+3;j++)
            {
                if(board[i][j]==val) return false;
            }
        }
        return true;
    }

    void solveSudoku(vector<vector<char>>& board) 
    {
        backtracking(board);
    }
};

原理思路:

        此题起始最大的难点其实就是维度上了,因为这里我们不仅要在二维的棋盘上找到没有填入数字的位置,还要找出要填入的正确的数字,所以虽然此题用了递归和回溯,但是还是要写好几层循环,下面讲讲具体如何实现的。

        1、这里我们只用得到一个结果,所以我们回溯函数的返回值为bool类型,后面我们会设置一个flag来接收,判断若已经找到一个结果,我么直接停止寻找。

        2、回溯函数的参数只有一个board,因为我们每次寻找位置都是从头开始寻找,就不再传入额外参数来寻找开始位置了。

        3、回溯函数的终止条件,这里我们不用像其他题一样在开头给出终止条件,我们写在最后,当我们找不到位置时,没有进行下一次循环,说明棋盘格已经被填满了,就找到结果了,返回true。

        4、就开始写寻找位置和寻找合适的数的代码逻辑了,同时还要判断填入数字是否有效,若有效才进行下一次递归,否则直接返回false,重新寻找,很简单,直接给出代码:

//两层循环找位置
       for(int row=0;row<board.size();row++)
       {
           for(int col=0;col<board[0].size();col++)
           {
               //找到位置
               if(board[row][col]=='.')
               {
                    //选择1~9的数字
                    for(char i='1';i<='9';i++)
                    {
                        //判断此数是否有效
                        if(isvaild(row,col,i,board))
                        {
                            board[row][col]=i;
                            bool flag=backtracking(board);//递归
                            //这里只用寻找一个符合的结果就行,找到后直接返回
                            if(flag==true)
                            {
                                return true;
                            }
                            board[row][col]='.';//回溯
                        }                       
                    }
                    return false;//都不成立,返回false
               }              
           }          
       }

        5、然后就是判断当前位置的数字是否有效了,根据题意也是很好写出的,如下:‘

     bool isvaild(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 i=0;i<9;i++)
        {
            if(board[i][col]==val) return false;
        }
        //9格内是否有重复
        int startrow=(row/3)*3;//起始行
        int startcol=(col/3)*3;//起始列
        for(int i=startrow;i<startrow+3;i++)
        {
            for(int j=startcol;j<startcol+3;j++)
            {
                if(board[i][j]==val) return false;
            }
        }
        return true;
    }

        其实看起来很难,如果逻辑搞清楚,其实还是很好写出的。回溯其实就是模拟嵌套循环的过程,适合解决的就是不知道要嵌套循环多少次的情况,比如这题,我们不知道没有填入数字的棋盘格有多少,这里为什么和其他题不一样,而是是嵌套了三层循环才开始递归回溯呢?其实上面也解释了,我们要在二维上找位置,还要找数字,如果还是不太理解的话,当写回溯的题,可以假设一下棋盘格空余位置的数量是固定的,也就是假设循环次数是固定的,看看若不用回溯的话我们如何写,然后找出循环嵌套重复的代码,你就知道为什么回溯要这样写了。

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

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

相关文章

分布式链路追踪SkyWalking进阶实战之RPC上报和WebHook通知(三)

目录 1.自定义SkyWalking链路追踪配置 1.1 什么是TraceId 1.2 使用的背景 1.3 编码 2.SkyWalking-RocketBot性能剖析 3.SkyWalking链路追踪-日志和RPC上报实战 4.源码部署 Apache SkyWalking 5.SkyWalking链路追踪-告警模块和WebHook通知《上》 6.SkyWalking链路追踪-…

对技术类的管理和绩效的一些想法

大家好&#xff1a; 我是烤鸭。看完春晚小品的心情(除了神马组合)&#xff0c;就跟下面这哥们一样&#xff0c;尬的抠脚。再加上初一跟家人出去一趟&#xff0c;消费是真的复苏了&#xff0c;哪哪都排队。本来还想去洗温泉&#xff0c;给商家打电话一直占线…就能想象有多少人了…

7. 初步认识线程同步

前言&#xff1a;一旦接触到多线程编程&#xff0c;那么线程之间的同步就显得非常重要了。c/c#/java等高级语言都有自己的线程库&#xff0c;当然也提供了线程同步的API接口。打个比方&#xff0c;在C/QT中&#xff0c;线程的同步有以下几种方式&#xff1a;互斥锁、信号量、条…

2、SPSS的基本知识

目录 一、SPSS软件的安装和启动 二、SPSS的基本操作环境 &#xff08;1&#xff09;数据编辑窗口&#xff08;主程序窗口&#xff09; &#xff08;2&#xff09;SPSS结果输出窗口 三、SPSS软件的退出 四、SPSS软件的三种基本使用方式 五、SPSS数据的结构和定义方法 1.…

单链表——简单的增删查改

前言&#xff1a;上次介绍了顺序表&#xff0c;这次我要分享对单链表的一些简单理解&#xff0c;主要框架与上次大致相同&#xff0c;内容主要是单链表的增删查改&#xff0c;适用于初学者&#xff0c;之后会继续更新一些更深入的内容。同时&#xff0c;这也仅仅是我个人对所学…

不完全微分PID控制算法及仿真

在 PID控制中&#xff0c;微分信号的引入可改善系统的动态特性&#xff0c;但也易引进高频干扰&#xff0c;在误差扰动突变时尤其显出微分项的不足。若在控制算法中加入低通滤波器&#xff0c;则可使系统性能得到改善。克服上述缺点的方法之一是在 PID算法中加入一个一阶惯性环…

pdf如何合并,用这个方法又快又好使

我们在整理文档的时候经常被要求最后提交的得是PDF&#xff0c;所以有时候手头上的文档有多份&#xff0c;但最后还得整合成一份PDF才行。合并PDF后我们才可以进行后续的操作&#xff0c;所以学会如何快速合并PDF很重要。要把多个文档整合到一起&#xff0c;借助下面这些工具就…

一文带你了解学习python的用处及好处,建议收藏

目录 学习Python能做什么&#xff1f; Python的用途有哪些 普通人学习python有什么好处 用处&#xff0c;很重要的呢 今天这一讲很关键&#xff0c;如果你都不知道python的好处&#xff0c;以及python的用处&#xff0c;那你python就算是白学了 学习Python能做什么&#xf…

【目标检测】------rcnn、fastrcnn、fasterrcnn

RCNN流程图 sppnet流程图 fastRcnn fasterrcnn网络 RPN&#xff08;Region Proposal Network&#xff09;是Faster-RCNN网络用于提取预选框&#xff08;也就是RCNN中使用selective search算法进行Region Proposal的部分&#xff09;&#xff0c;我们知道RCNN及Fast-RCNN中一个…

【Maven】属性管理

1. 属性 问题导入 定义属性有什么好处&#xff1f; 1.1 属性配置与使用 ①&#xff1a;定义属性 <!--定义自定义属性--> <properties><spring.version>5.2.10.RELEASE</spring.version><junit.version>4.12</junit.version> </prop…

第二章——CSS基础选择器,标签选择器,类选择器, id 选择器,通配符选择器

文章目录2.1 CSS选择器的作用2.2 CSS选择器分类2.3 CSS 基础选择器分类2.4 标签选择器2.5 类选择器2.5.1 多类名选择2.6 id选择器2.7 id选择器与类选择器的区别‘2.8 通配符选择器2.9 选择器对比2.1 CSS选择器的作用 选择器(选择符)就是根据不同需求把不同的标签选出来这就是选…

python图像处理(直方图增强)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】 前面几篇文章谈到了对图像的处理,但是它们大多数都是对图像像素进行一些时空的转换,本身像素的内容并没有发生转变。比如旋转,镜像、移动、放大、缩小等等,像素还是这些像素,只…

Pytorch基础知识

Pytorch 基础知识 1.1 张量的概念 在PyTorch中&#xff0c;张量&#xff08;Tensor&#xff09;属于一种数据结构&#xff0c;它可以使一个标量、一个向量、一个矩阵&#xff0c;甚至是更维度的数组。类似于numpy中的数组 (ndarray),并且它们是可以相互转化的&#xff0c;在P…

python3:openpyxl解析和生成excel的常用方法

解析 打开已经存在的工作簿 openpyxl.load_workbook()方法 from openpyxl import load_workbookwb2 load_workbook(test.xlsx) print wb2.get_sheet_names() [Sheet2, New Title, Sheet1] 生成 创建一个工作簿 from openpyxl import Workbook# 一个工作簿(workbook)在创建…

kafka的关键细节 以及 分区和主题的概念

文章目录Kafka中的关键细节1.消息的顺序存储2. 单播消息的实现3.多播消息的实现4.查看消费组及信息主题、分区的概念1.主题Topic2.partition分区Kafka中的关键细节 1.消息的顺序存储 消息的发送方会把消息发送到broker中&#xff0c;broker会存储消息&#xff0c;消息是按照发…

python本科毕业设计基于神经网络的虚假评论识别系统源码,含模型及数据

主要函数&#xff1a; 1.corpusprocess原始语料处理函数 2.train_word2vec生成word2vec向量 3.generate_id2wec获得索引的w2id,和嵌入权重embedding_weights 4.prepare_data 数据预处理 完整代码下载地址&#xff1a;python本科毕业设计基于神经网络的虚假评论识别系统源码 代…

多线程(初阶)——多线程基础

多线程(初阶)——多线程基础 文章目录多线程(初阶)——多线程基础1.认识线程2.多线程程序2.1 第一个Java多线程程序2.2 观察线程的详细情况2.3 sleep方法2.4 run和start方法的区别3.创建线程3.1 继承Thread类3.2实现Runnable接口3.3 通过匿名内部类创建线程3.4通过实现Runnable…

【目标检测】------yolox网络结构

YOLOX网络结构图 卷积和池化计算器&#xff1a; http://www.sqflash.com/cal.html

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面

总结&#xff1a; 找到解析器后&#xff0c;用解析器去解析参数&#xff0c;都使用了resolveArgument()中以下方法 mavContainer.getModel(); mavContainer:模型和视图容器 视图&#xff1a;页面请求要返回一个地方&#xff0c;这个地方的地址叫视图 。比如要到/sucess 模…

CV——day70 零基础学YOLO:YOLOv1

YOLO系列1. 不同阶段算法优缺点分析2. IOU指标计算3. MAP指标计算**指标分析**如何计算MAP4 YOLOv14.1 YOLOv1核心思想4.2 YOLOv1网络架构那么&#xff0c;7 * 7 * 30的输出是怎么来呢&#xff1f;4.3 损失函数4.3.1 位置误差4.3.2 置信度误差(含object)4.3.3 置信度误差(不含o…