LeetCode 第37题:解数独
1.LeetCode 第10题:正则表达式匹配2.LeetCode 第1题:两数之和3.LeetCode 第2题:两数相加4.LeetCode 第3题:无重复字符的最长子串5.LeetCode 第4题:寻找两个正序数组的中位数6.LeetCode 第8题:字符串转换整数 (atoi)7.LeetCode 第7题:整数反转8.LeetCode 第6题:Z字形变换9.LeetCode 第5题:最长回文子串10.LeetCode 第9题:回文数11.LeetCode 第11题:盛最多水的容器12.LeetCode 第12题:整数转罗马数字13.LeetCode 第13题:罗马数字转整数14.LeetCode 第14题:最长公共前缀15.LeetCode 第15题:三数之和16.LeetCode 第16题:最接近的三数之和17.LeetCode 第17题:电话号码的字母组合18.LeetCode 第18题:四数之和19.LeetCode 第19题:删除链表的倒数第N个结点20.LeetCode 第20题:有效的括号21.LeetCode 第21题:合并两个有序链表22.LeetCode 第22题:括号生成23.LeetCode 第23题:合并K个升序链表24.LeetCode 第24题:两两交换链表中的节点25.LeetCode 第25题:K 个一组翻转链表26.LeetCode 第26题:删除有序数组中的重复项27.LeetCode 第27题:移除元素28.LeetCode 第28题:找出字符串中第一个匹配项的下标29.LeetCode 第29题:两数相除30.LeetCode 第30题:串联所有单词的子串31.LeetCode 第31题:下一个排列32.LeetCode 第32题:最长有效括号33.LeetCode 第33题:搜索旋转排序数组34.LeetCode 第34题:在排序数组中查找元素的第一个和最后一个位置35.LeetCode 第35题:搜索插入位置36.LeetCode 第36题:有效的数独
37.LeetCode 第37题:解数独
38.LeetCode 第38题:外观数列39.LeetCode 第39题:组合总和40.LeetCode 第40题:组合总和 II41.LeetCode 第41题:缺失的第一个正数LeetCode 第37题:解数独
题目描述
编写一个程序,通过填充空格来解决数独问题。
数独的解法需 遵循如下规则:
- 数字 1-9 在每一行只能出现一次。
- 数字 1-9 在每一列只能出现一次。
- 数字 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]
是一个数字或者'.'
- 题目数据 保证 输入数独仅有一个解
解题思路
方法:回溯算法
这是一个经典的回溯算法问题,我们需要尝试填充每个空格,并在发现错误时及时回溯。
关键点:
- 使用回溯法尝试每个可能的数字
- 优化验证过程,避免重复检查
- 使用位运算加速判断
具体步骤:
- 预处理阶段:
- 记录每行、每列、每个3x3方格中已有的数字
- 找到所有需要填充的位置
- 回溯过程:
- 对每个空位尝试1-9的数字
- 验证当前数字是否有效
- 继续填充下一个位置或回溯
时间复杂度:O(9^m),m为空格数量
空间复杂度:O(m),递归栈的深度
图解思路
回溯过程分析表
步骤 | 当前位置 | 尝试数字 | 结果 | 说明 |
---|---|---|---|---|
初始状态 | (0,2) | 1-9 | 4可用 | 第一个空格位置 |
继续填充 | (0,3) | 1-9 | 6可用 | 成功填入4后继续 |
回溯 | (2,0) | 1-9 | 1可用 | 前面填充正确,继续 |
完成 | (8,8) | - | 成功 | 所有空格已填满 |
状态记录表
数据结构 | 用途 | 实现方式 | 优势 |
---|---|---|---|
行状态 | 记录每行数字 | 位运算 | 快速查找和更新 |
列状态 | 记录每列数字 | 位运算 | 空间效率高 |
宫状态 | 记录3x3宫数字 | 位运算 | 验证速度快 |
位运算示例
操作 | 二进制表示 | 说明 |
---|---|---|
添加数字5 | 00010000 | 第5位置1 |
删除数字5 | 11101111 | 第5位置0 |
检查数字5 | &00010000 | 与运算判断 |
代码实现
public class Solution {
private int[] rows = new int[9];
private int[] cols = new int[9];
private int[] boxes = new int[9];
private bool solved = false;
public void SolveSudoku(char[][] board) {
// 初始化状态
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (board[i][j] != '.') {
int num = board[i][j] - '0';
int pos = 1 << (num - 1);
rows[i] |= pos;
cols[j] |= pos;
boxes[(i/3)*3 + j/3] |= pos;
}
}
}
// 开始回溯
Backtrack(board, 0, 0);
}
private bool Backtrack(char[][] board, int row, int col) {
if (col == 9) {
row++;
col = 0;
}
if (row == 9) return true;
if (board[row][col] != '.') {
return Backtrack(board, row, col + 1);
}
int boxIndex = (row/3)*3 + col/3;
for (int num = 1; num <= 9; num++) {
int pos = 1 << (num - 1);
if ((rows[row] & pos) == 0 &&
(cols[col] & pos) == 0 &&
(boxes[boxIndex] & pos) == 0) {
board[row][col] = (char)(num + '0');
rows[row] |= pos;
cols[col] |= pos;
boxes[boxIndex] |= pos;
if (Backtrack(board, row, col + 1)) {
return true;
}
board[row][col] = '.';
rows[row] &= ~pos;
cols[col] &= ~pos;
boxes[boxIndex] &= ~pos;
}
}
return false;
}
}
执行结果
- 执行用时:92 ms
- 内存消耗:38.2 MB
代码亮点
- 🎯 使用位运算优化数字判断
- 💡 预处理初始状态,避免重复计算
- 🔍 高效的回溯策略
- 🎨 清晰的代码结构和命名
常见错误分析
- 🚫 回溯条件判断错误
- 🚫 状态重置不完整
- 🚫 位运算操作失误
- 🚫 边界条件处理不当
解法对比
解法 | 时间复杂度 | 空间复杂度 | 优点 | 缺点 |
---|---|---|---|---|
暴力回溯 | O(9^m) | O(m) | 实现简单 | 效率低 |
位运算优化 | O(9^m) | O(1) | 性能好 | 代码复杂 |
Dancing Links | O(9^m) | O(n^2) | 最优解法 | 实现难度大 |
相关题目
- LeetCode 36. 有效的数独 - 中等
- LeetCode 51. N 皇后 - 困难
- LeetCode 52. N皇后 II - 困难
- LeetCode 79. 单词搜索 - 中等
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了