LeetCode算法题解(回溯,难点)|LeetCode37. 解数独

news2024/10/6 0:29:06

LeetCode37. 解数独

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

算法分析:

利用回溯法确定并放置每个格子能放值的数字。

回溯的返回值类型为boolean,只要找到一个符合的条件就直接返回true。

利用双重for循环搜索每个格子的位置,并判断该格子是否是空格,如果不是空格不是空格直接跳过这一个格子。

   public boolean backTravel(int x, int y, char[][] board) {
       for(int i = x; i < board.length; i++) {
           for(int j = y; j < board[0].length; j++) {//遍历每一个格子
               if(board[i][j] != '.') continue;
               ....
           }
       }
   }

如果该格子是空格子,判断该格子是否可以放入1-9当中的数字如果可以,放入数字,然后递归、回溯。

for(char ch = '1'; ch <= '9'; ch++) {
   if(canPut(ch, i, j, board)) {//判断当前空白格是否可以用1-9数字来填入
      board[i][j] = ch;//如果可以将数字字符填入空格内
      if(backTravel(i, y, board)) return true;//然后递归,如果递归返回的是true那么说明找到了解决方案,直接返回true
      board[i][j] = '.';//如果没找到,进行回溯
   }
}

判断是否可以放数字的函数:

public boolean canPut(char ch, int x, int y, char[][] board) {//判断当下坐标是否可以放置ch
        for(int i = 0; i < board.length; i++) {//判断这一列是否出现过ch
            ...
        }
        for(int j = 0; j < board[0].length; j++) {//判断这一行是否出现过ch
            ...
        }
        //找到当前格子所属的3*3宫格的左上角坐标
        int startx = (x/3)*3;
        int starty = (y/3)*3;
        for(int i = startx; i < startx + 3; i++) {//判断当前坐标所属的3*3宫格内是否出现ch
            for(int j = starty; j < starty + 3; j++) {
                ...
            }
        }
        return true;
    }

完整的代码如下:

class Solution {
    public boolean canPut(char ch, int x, int y, char[][] board) {//判断当下坐标是否可以放置ch
        for(int i = 0; i < board.length; i++) {//判断这一列是否出现过ch
            if(board[i][y] == ch)
            return false;
        }
        for(int j = 0; j < board[0].length; j++) {//判断这一行是否出现过ch
            if(board[x][j] == ch)
            return false;
        }
        //找到当前格子所属的3*3宫格的左上角坐标
        int startx = (x/3)*3;
        int starty = (y/3)*3;
        for(int i = startx; i < startx + 3; i++) {//判断当前坐标所属的3*3宫格内是否出现ch
            for(int j = starty; j < starty + 3; j++) {
                if(board[i][j] == ch) 
                return false;
            }
        }
        return true;
    }
    public boolean backTravel(int x, int y, char[][] board) {
       for(int i = x; i < board.length; i++) {
           for(int j = y; j < board[0].length; j++) {//遍历每一个格子
               if(board[i][j] != '.') continue;
               for(char ch = '1'; ch <= '9'; ch++) {
                   if(canPut(ch, i, j, board)) {//判断当前空白格是否可以用1-9数字来填入
                       board[i][j] = ch;//如果可以将数字字符填入空格内
                       if(backTravel(i, y, board)) return true;//然后递归,如果递归返回的是true那么说明找到了解决方案,直接返回true
                       board[i][j] = '.';//如果没找到,进行回溯
                   }
               }
               //1-9都不能填入当前空格,说明找不到解诀数独的方法,返回false
               return false;
           }
       }
       //遍历完了都没有返回false,说明找到了合适的棋盘位置,返回true
       return true;
    }
    public void solveSudoku(char[][] board) {
        backTravel(0, 0, board);
    }
}

总结

这道题的难点是对每个空格子该放入哪个数字,以及什么时候结束回溯的操作。

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

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

相关文章

【获取cookie的真实到期时间】

获取cookie的真实到期时间 from datetime import datetime print(datetime.fromtimestamp(1734148606))

客户服务中可能造成客户流失的 5 个错误

在商业活动中&#xff0c;客户服务是影响企业的重要因素之一。一位不满意的客户可能会带来不良的口碑&#xff0c;影响其他潜在客户的购买决策&#xff0c;甚至导致客户流失。因此&#xff0c;提高客户满意度和降低客户流失率成为企业非常关注的问题。这篇文章将从五个方面&…

安卓编译命令mm和mmm的区别(mm编译当前工作目录,mmm可编译指定目录)

文章目录 1. mm示例 2. mmm示例 注意 在Android操作系统的源代码编译过程中&#xff0c; mm和 mmm是两个用于构建部分代码的常用命令。它们都属于Android build system提供的命令集合&#xff0c;但用途略有不同&#xff1a; 1. mm mm&#xff08;make module&#xff09;命…

【C++】STL 标准模板库 ③ ( STL 容器简介 | STL 容器区别 | STL 容器分类 | 常用的 STL 容器 )

文章目录 一、STL 容器简介1、STL 容器区别2、STL 容器分类3、常用的 STL 容器 一、STL 容器简介 1、STL 容器区别 STL 容器 用于管理 一组 数据元素 , 不同类型的 STL 容器 的区别 主要是 节点 和 节点之间的关系模型 不同 ; 容器的内存空间是否连续 : 向量 vector 的内存空间…

数据结构之二叉树OJ(C++)

根据二叉树创建字符串 606. 根据二叉树创建字符串 - 力扣&#xff08;LeetCode&#xff09; 题目的要求是给我们一棵二叉树,让我们用前序遍历的方式把它转换成一个由整数和括号组成的字符串。 我们观察它给的用例会发现其实整数就是每个结点的值,括号其实是把每棵树的左右子树…

[EFI]戴尔Latitude 5310电脑 Hackintosh 黑苹果efi引导文件

硬件型号驱动情况 主板戴尔Latitude 5310 处理器Intel Core i5-10210U(1.6GHz/L3 6M)已驱动 内存8GB已驱动 硬盘三星 MZVLW1T0HMLH-000L2 (1024 GB / 固态硬盘)已驱动 显卡Intel UHD620已驱动 声卡瑞昱 Audio ALC299 英特尔 High Definition Audio 控制器已驱动 网卡RT…

Git Gui的使用+关于SSH协议和克隆对应文件代码+IDEA集成Git等

目录 一、Git图形化界面的使用 1.1 前期准备 1.2 Git图形化界面的使用 1.2.1 文件代码克隆 1.2.2 文件GIt管理效果查看 1.2.3 Git Gui页面详情图解 1.2.4 Git Gui功能演示效果 &#xff08;1&#xff09;暂存 &#xff08;2&#xff09;提交与注释 &#xff08;3&…

刚安装的MySQL使用Navicat操作数据库遇到的问题

刚安装的MySQL使用Navicat操作数据库遇到的问题 一、编辑连接保存报错二、打开数据表很慢三、MySQL的进程出现大量“sleep”状态的进程四、执行sql脚本报错&#xff0c;部分表导不进去五、当前MySQL配置文件 一、编辑连接保存报错 连接上了数据库&#xff0c;编辑连接保存报错…

分享76个Python管理系统源代码总有一个是你想要的

分享76个Python管理系统源代码总有一个是你想要的 下载链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;8888 项目名称 cms是一个基于kubernetes官方python SDKkubernetes开发的一个容器运维系统 Django erp 后台管理系统&#xff0c;仅限学习使用&#xff0c;不…

如何查看网站的https的数字证书

如题 打开Chrome浏览器&#xff0c;之后输入想要抓取https证书的网址&#xff0c;此处以知乎为例点击浏览器地址栏左侧的锁的按钮&#xff0c;如下图 点击“连接是安全的”选项&#xff0c;如下图 点击“证书有效”选项卡&#xff0c;如下图 查看基本信息和详细信息 点击详细信…

【Java】本地开发环境正常、测试或生产环境获取的文件路径不对的问题

引 Java 中经常获取本地文件或者resource下的文件&#xff0c;要获取文件&#xff0c;首先要获得本地路径。 Java 本身或一些开源工具包都提供了很多获取路径的方法。但使用时经常遇到本地开发环境正常、测试或生产环境获取的文件路径不对的问题。 本文将列出几种常见的获取…

minicom----linux 调试工具

简单了解minicom 工具&#xff0c;安装、使用&#xff1a; (6条消息) minicom 的使用_002237的博客-CSDN博客 usb 转uart 串口&#xff1a; 可以烧版本&#xff0c;可以打印。 如果在ttyusb5 打印不出来&#xff0c;换个口插&#xff0c;并把其它的打印串口拔掉。 忘了上次写…

动态规划-构建乘积数组

** 描述 给定一个数组 A[0,1,…,n-1] ,请构建一个数组 B[0,1,…,n-1] ,其中 B 的元素 B[i]A[0]A[1]…*A[i-1]A[i1]…*A[n-1]&#xff08;除 A[i] 以外的全部元素的的乘积&#xff09;。程序中不能使用除法。&#xff08;注意&#xff1a;规定 B[0] A[1] * A[2] * … * A[n-1…

《011.SpringBoot+vue之汽车销售管理系统》

《011.SpringBootvue之汽车销售管理系统》 项目简介 [1]本系统涉及到的技术主要如下&#xff1a; 推荐环境配置&#xff1a;DEA jdk1.8 Maven MySQL 前后端分离; 后台&#xff1a;SpringBootMybatis; 前台&#xff1a;vueElementUI; [2]功能模块展示&#xff1a; 1.登录 2.销…

LeetCode刷题总结(一)

文章目录 前言题型排序问题动态规划 前言 本文把刷题过程中的总结记下来&#xff0c;方便未来回顾的时候继续拓展。 题型 排序问题 排序问题的解决方法有很多。对于简单算法来说&#xff0c;最重要的是记住思路&#xff1b;对于高级算法来说&#xff0c;最重要的是记住细节…

linux下搭建gperftools工具分析程序瓶颈

1. 先安装 unwind //使用root wget https://github.com/libunwind/libunwind/archive/v0.99.tar.gz tar -xvf v0.99.tar.gz cd libunwind-0.99 autoreconf --force -v --install ./configure make sudo make install2. 安装gperftools wget https://github.com/gp…

Linux下内网穿透实现云原生观测分析工具的远程访问

&#x1f4d1;前言 本文主要是Linux下内网穿透实现云原生观测分析工具的远程访问设置的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是青衿&#x1f947; ☁️博客首页&#xff1a;CSDN主页放风讲故事 &…

Redis为什么要使用SDS作为基本数据结构

Redis为什么要使用SDS作为基本数据结构 Redis SDS与C语言中字符串的对比二进制安全兼容部分C字符串函数 Redis SDS与C语言中字符串的对比 SDS中保存了字符串的长度属性&#xff0c;我们在获取字符串长度是的时间复杂度为O(1)&#xff0c;而C中字符串则需要对字符串进行遍历时间…

【Spring之底层核心架构概念解析】

文章目录 一、BeanDefinition二、BeanDefinitionReader2.1、AnnotatedBeanDefinitionReader2.2、XmlBeanDefinitionReader 五、ClassPathBeanDefinitionScanner六、BeanFactory七、ApplicationContext7.1、AnnotationConfigApplicationContext7.2、ClassPathXmlApplicationCont…

LeetCode 26. 删除有序数组中的重复项 简单

题目 - 点击直达 1. 26. 删除有序数组中的重复项 简单1. 题目详情1. 原题链接2. 题目要求3. 基础框架 2. 解题思路1. 思路分析2. 时间复杂度3. 代码实现 1. 26. 删除有序数组中的重复项 简单 1. 题目详情 给你一个 非严格递增排列 的数组 nums &#xff0c;请你 原地 删除重复…