news 2026/4/23 8:45:41

回溯算法专题(十):二维递归的完全体——暴力破解「解数独」

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
回溯算法专题(十):二维递归的完全体——暴力破解「解数独」

哈喽各位,我是前端小L。

欢迎来到我们的回溯算法专题第十篇!数独游戏大家应该都玩过,规则极其“简单粗暴”:

  1. 数字 1-9在每一行只能出现一次。

  2. 数字 1-9在每一列只能出现一次。

  3. 数字 1-9在每一个以粗实线分隔的3x3 宫内只能出现一次。

我们现在的任务是:写一个程序,把一个残缺的数独填完。 这道题和之前最大的不同在于:我们要找的不是“所有解”,而是“一个解”。一旦找到,立刻停止!这意味着我们的递归函数要有返回值 (bool),用来告诉上一层:“搞定了,别试了,快撤!”

力扣 37. 解数独

https://leetcode.cn/problems/sudoku-solver/

题目分析:

  • 输入9x9的二维字符数组board。空位用'.'表示。

  • 目标:原地修改board,填入唯一的一个可行解。

核心思维:如何遍历二维空格?

在 N 皇后中,我们通过backtrack(row + 1)来控制递归深度。 但在数独中,空格是散落在棋盘各处的。 我们通常采用双重循环 + 递归的策略:

递归逻辑(伪代码):

Plaintext

function backtrack(board): for i from 0 to 8: for j from 0 to 8: if board[i][j] is Empty: // 发现一个坑!尝试填 1-9 for k from '1' to '9': if isValid(i, j, k): 填入 k if backtrack(board) is True: return True // 找到了!一路绿灯返回 撤销 k (回溯) return False // 1-9 都试过了都不行,说明前面的步骤填错了,无解 return True // 遍历完所有格子没返回 False,说明填满了!

注意到了吗?这个递归结构和之前的很不一样。它在函数内部就开启了对整个棋盘的扫描。一旦发现空格,就通过递归去填下一个空格。

isValid的九宫格判定

判断行和列很简单。难点在于判断3x3 九宫格。 对于任意坐标(r, c),它所属的 3x3 宫的左上角坐标是:

  • startRow = (r / 3) * 3

  • startCol = (c / 3) * 3通过这两个基准点,我们可以遍历该宫内的 9 个格子。

代码实现 (C++)

C++

#include <vector> using namespace std; class Solution { private: // 判断在 board[row][col] 填入 val 是否合法 bool isValid(int row, int col, char val, vector<vector<char>>& board) { // 1. 检查行 for (int j = 0; j < 9; j++) { if (board[row][j] == val) return false; } // 2. 检查列 for (int i = 0; i < 9; i++) { if (board[i][col] == val) return false; } // 3. 检查 3x3 九宫格 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; } // 返回值 bool:表示是否找到了一组解 // 如果找到,立即停止后续搜索 bool backtrack(vector<vector<char>>& board) { // 遍历整个棋盘寻找空格 for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { // 如果发现空格 if (board[i][j] == '.') { // 尝试填入 '1' 到 '9' for (char k = '1'; k <= '9'; k++) { if (isValid(i, j, k, board)) { // 做选择 board[i][j] = k; // 递归:如果后续的填充成功了,那我也直接返回 true if (backtrack(board)) return true; // 撤销选择 (回溯) board[i][j] = '.'; } } // 9个数字都试完了还不行,说明这个空格在这个局面下无解 // 或者是前面的步骤填错了,需要回溯 return false; } } } // 如果两个循环跑完都没有返回 false,说明没有空格了(填满了) return true; } public: void solveSudoku(vector<vector<char>>& board) { backtrack(board); } };

深度复杂度分析

  • 时间复杂度:非常恐怖。

    • 数独的空白格可能有 M 个。

    • 每个格子有 9 种选择。

    • 理论上限是 O(9M)。

    • 但由于数独的约束非常强(每填一个数,其他格子的选择就少很多),实际运行并不慢。

  • 空间复杂度:O(M)。

    • 递归栈的深度等于空白格的数量。

总结:回溯算法的“毕业设计”

恭喜你!这道题通过,标志着你已经攻克了回溯算法最险峻的山峰。

让我们回顾一下回溯算法的“进化史”:

  1. 组合/子集startIndex控制不回头,path收集结果。

  2. 排列used数组控制不重复选,关注顺序。

  3. 切割startIndex作为切割线,判断子串合法性。

  4. 去重sort+nums[i] == nums[i-1]剪掉树层重复。

  5. 棋盘

    • N 皇后:一维决策(行),二维约束。

    • 解数独:二维决策(每个格子),找唯一解(bool 返回值)。

这一套组合拳打下来,所有的暴力搜索问题在你面前都将无所遁形。

接下来学什么?我们已经完成了:DP(内功)、图论(招式)、回溯(暴力美学)。 接下来,我建议我们稍微“换个口味”,去探索一下算法面试中代码量最少,但思维最巧妙的领域——贪心算法 (Greedy)

下一篇,我们将从经典的**“分发饼干”**开始,看看如何用“局部最优”推导出“全局最优”。准备好你的直觉了吗?

下期见!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 8:45:40

java基础-Java Queue 接口

Queue 是 Java 集合框架中的一个重要接口&#xff0c;位于 java.util 包中&#xff0c;它表示一个先进先出&#xff08;FIFO&#xff09;的队列数据结构。Queue 接口继承了 Collection 接口&#xff0c;并定义了一组专门用于队列操作的方法。Queue 接口的主要特点先进先出(FIFO…

作者头像 李华
网站建设 2026/4/23 8:44:53

基于Java+ vue校园快递代取系统(源码+数据库+文档)​

校园快递代取 目录 基于springboot vue校园快递代取系统 一、前言 二、系统功能演示 详细视频演示 三、技术选型 四、其他项目参考 五、代码参考 六、测试参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 基于springboot vue校园快递代取系统 一、前言…

作者头像 李华
网站建设 2026/4/23 8:45:05

BrowserUse10-源码-FileSystem模块-整理

BrowserUse10-源码-FileSystem模块-整理FileSystem模块-整理 1-源代码部分import asyncio import base64 import os import re import shutil from abc import ABC, abstractmethod from concurrent.futures import ThreadPoolExecutor from pathlib import Path from typing i…

作者头像 李华
网站建设 2026/4/18 10:00:02

把钱交给理财专家 —— 基金:普通人的财富增值捷径

把钱交给理财专家 —— 基金&#xff1a;普通人的财富增值捷径很多人都有这样的困惑&#xff1a;想理财却没时间研究股票、看不懂债券条款、怕踩雷不敢买理财&#xff0c;眼睁睁看着钱躺在活期账户里 “缩水”。其实&#xff0c;解决这个问题的答案很简单 ——基金。它就像 “大…

作者头像 李华
网站建设 2026/4/19 19:36:07

Python新手必看:YAML配置文件入门指南

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 编写一个面向初学者的Python YAML教程代码&#xff0c;包含以下内容&#xff1a;1) 安装PyYAML库的方法&#xff1b;2) 基本YAML语法示例&#xff1b;3) Python读取YAML文件的3种方…

作者头像 李华
网站建设 2026/4/18 9:56:12

Elasticsearch面试小白指南:从零开始

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个面向Elasticsearch初学者的交互式学习应用&#xff0c;从基本概念&#xff08;如倒排索引、文档类型&#xff09;开始&#xff0c;逐步引导用户理解核心功能。包含简单的可…

作者头像 李华