前言
关于 LeetCode 数组类型题目的相关解法,可见LeetCode 数组类型题目做前必看,分类别解法总结了题目,可以用来单项提高。觉得有帮助的话,记得多多点赞关注哦,感谢!
题目描述
编写一个程序,通过填充空格来解决数独问题。
数独的解法需 遵循如下规则:
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)
数独部分空格内已填入了数字,空白格用 '.' 表示。
示例:
输入
输出
链接:leetcode-cn.com/problems/su…
题解
采用 DFS + backtracking(回溯) 的方法.
首先, 构建三个标记数组, rows, cols, boxes, 分别表示 行, 列, 子格子, 其中每个标记数组的大小都为 9×10 并且初始化每个元素为0. 那么 i, j 表示该行(列, 子格子)中的数字 j 是否被使用过, 0代表未使用, 1代表使用过了.比如, rows[0][3] = 1 代表 board 中第0行数字3已经被使用过了. 那么我们就可以利用这三个标记数组来遍历插入数字.
那么如何遍历呢?
根据 board 初始值, 我们可以将 rows, cols, boxes 标记数组初始化, 将已经在棋盘上的数字在各自的标记数组中置1. 然后依次从 1-9 的数字中, 找出符合 rows, cols, boxes 三个标志位均为 0 的数字, 并将其填入 board 中, 标志位置为1. 之后, 问题就变成在已知目前的 board 情况下, 该如何填满 board, 即递归调用, 也就是** dfs**. 当递归调用不满足条件时, 需要将 board 恢复原状, 不影响下个数组填入 board 中, 就是回溯的过程.
递归终止条件为: 递归调用到了行数为9的时候, 这时候说明board 0-8 行
已经填好了, 已经得到符号要求的解了.
代码见下方:
/**
* @param {character[][]} board
* @return {void} Do not return anything, modify board in-place instead.
*/
var solveSudoku = function(board) {
// 设置标记数组
rows = Array.from({ length: 9 }, () => new Array(10).fill(0))
cols = Array.from({ length: 9 }, () => new Array(10).fill(0))
boxes = Array.from({ length: 9 }, () => new Array(10).fill(0))
// 根据board初始化标记数组
for (let i = 0; i < 9; ++i) {
for (let j = 0; j < 9; ++j) {
const c = board[i][j]
if (c !== '.') {
const n = c - '0'
// 计算子格子的下表
const indexSubBox = Math.floor(i / 3) * 3 + Math.floor(j / 3)
rows[i][n] = 1
cols[j][n] = 1
boxes[indexSubBox][n] = 1
}
}
}
const fill = (board, x, y) => {
// 递归终止条件
if (x === 9) return true
// 下一个要递归的元素下表
const next_y = (y + 1) % 9
const next_x = (next_y === 0) ? x + 1 : x
if (board[x][y] !== '.') return fill(board, next_x, next_y)
// 1-9中找出合适的值填入board
for (let i = 1; i <= 9; ++i) {
const indexSubBox = Math.floor(x / 3) * 3 + Math.floor(y / 3)
// 符合要求的值
if (!rows[x][i] && !cols[y][i] && !boxes[indexSubBox][i]) {
// 填入board
rows[x][i] = 1
cols[y][i] = 1
boxes[indexSubBox][i] = 1
board[x][y] = i.toString()
// 递归调用(dfs)
if (fill(board, next_x, next_y)) return true
// 回溯, 恢复原状, 不影响填入下个符合要求的值
board[x][y] = '.'
rows[x][i] = 0
cols[y][i] = 0
boxes[indexSubBox][i] = 0
}
}
// 没有符合要求的解,返回false
return false
}
fill(board, 0, 0)
};