37. 解数独
https://leetcode-cn.com/problems/sudoku-solver
题目描述
编写一个程序,通过填充空格来解决数独问题。
一个数独的解法需遵循如下规则:
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
空白格用 '.' 表示。
提示:
给定的数独序列只包含数字 1-9 和字符 '.' 。
你可以假设给定的数独只有唯一解。
给定数独永远是 9x9 形式的。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sudoku-solver
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
方法 1: 回溯+哈希表
思路
这种题的思路就是,先在当前这步做一个决定,然后递归走下一步,每走一步做一个决定;如果走了死胡同,就回到上一步,改变当时的决定再走下一步;或者回到上上步,改变决定再重新往下走,总之就是把所有可能的决定的组合都尝试一遍,直到找到通路。
- 找到一个空格,填入一个数字,然后递归找另一个空格。
- 如果在这个空格没有数字可填,说明此路不通,那就原路返回到上一个空格(回溯)。
- 由于每个空格可填的数字可能不止一个,每个数字都得尝试一遍,然后在循环中递归找另一个空格。
- 怎么确定空格能填的数字?我们需要知道同一行、同一列、同一个小宫里已经填过的数字:
- 用一个
数组 + 哈希表
记录每行和每列已填的数字。 - 用一个
3*3 二维数组 + 哈希表
记录每个小宫已填的数字。 - 对于每个空格,尝试数字 1~9,排除记录在哈希表中的数字。
- 用一个
- 怎么根据坐标确定空格属于哪个
3*3
小宫?floor(x/3)
可以确定是第几行的小宫。floor(y/3)
可以确定是第几列的小宫。
其他看代码注释吧。
p.s. 不用哈希表,用数组记录已填数字的状态也行。
复杂度分析
- 时间复杂度: O ( 9 n ) O(9^n) O(9n),因为一共有 9 个数字,所以递归树可以看成是一个九叉树,这里九叉树的高度是数独表的格子总数 n,所以九叉树的节点最多有 O ( 9 n ) O(9^n) O(9n) 吧。
- 空间复杂度: O ( n ) O(n) O(n),n 是数独表的格子总数,递归栈最大深度,以及哈希表空间都是 n。
代码
JavaScript Code
/**
* @param {character[][]} board
* @return {void} Do not return anything, modify board in-place instead.
*/
var solveSudoku = function (board) {
// 记录每行已填的数字
const rows = matrix(9);
// 记录每列已填的数字
const cols = matrix(9);
// 记录每个小宫已填的数字
const boxes = matrix(3, 3);
// 记录所有空格子的坐标
const spaces =</