大约 2 分钟
这是一个经典的算法题,我们可以通过一次遍历来解决这个问题。
解题思路
我们需要验证数独的三个规则:
- 行规则:每一行只能出现一次数字 1-9。
- 列规则:每一列只能出现一次数字 1-9。
- 宫规则:每一个 3x3 的小宫格内只能出现一次数字 1-9。 我们可以使用 哈希表(或数组) 来记录数字的出现情况。具体来说,我们需要为行、列和宫各维护一组记录。 由于数字范围只是 1-9,使用数组来记录是最快速的(虽然使用
Set也可以,但数组效率更高)。 关于 3x3 宫格的索引计算: 这是本题的关键点。对于一个坐标(row, col),它属于哪个 3x3 宫格呢? 计算公式为:boxIndex = (row / 3) * 3 + (col / 3)(整数除法)。 例如:
(0, 0)-> 第 0 个宫(0, 4)-> 第 1 个宫(4, 4)-> 第 4 个宫
JavaScript 代码实现
/**
* @param {character[][]} board
* @return {boolean}
*/
var isValidSudoku = function(board) {
// 初始化记录数组
// rows[i][num] 表示第 i 行是否出现过数字 num
const rows = Array.from({ length: 9 }, () => Array(10).fill(false)); // 索引 1-9,0 位置不用
// cols[j][num] 表示第 j 列是否出现过数字 num
const cols = Array.from({ length: 9 }, () => Array(10).fill(false));
// boxes[k][num] 表示第 k 个 3x3 宫格是否出现过数字 num
const boxes = Array.from({ length: 9 }, () => Array(10).fill(false));
for (let i = 0; i < 9; i++) {
for (let j = 0; j < 9; j++) {
const val = board[i][j];
// 如果是空格 '.',直接跳过
if (val === '.') continue;
// 将字符数字转为整数 (例如 '5' -> 5)
const num = parseInt(val);
// 计算当前属于第几个 3x3 宫格
const boxIndex = Math.floor(i / 3) * 3 + Math.floor(j / 3);
// 检查是否已经存在
if (rows[i][num] || cols[j][num] || boxes[boxIndex][num]) {
// 如果在行、列或宫格中已经记录过该数字,说明重复,返回 false
return false;
}
// 标记该数字已出现
rows[i][num] = true;
cols[j][num] = true;
boxes[boxIndex][num] = true;
}
}
// 遍历结束,未发现重复,返回 true
return true;
};
复杂度分析
- 时间复杂度:$O(1)$。因为数独的大小固定为 9x9,我们需要遍历 81 个格子,操作次数是固定的常数,不随输入规模变化。
- 空间复杂度:$O(1)$。我们使用了三个 9x10 的二维数组来存储记录,空间占用也是固定的常数。