题目描述
判断一个 9×9 的数独是否有效。只需要根据以下规则验证已经填入的数字是否有效即可:
-
数字 1-9 在每一行只能出现一次;
-
数字 1-9 在每一列只能出现一次;
-
数字 1-9 在每一个以粗实线分隔的 3×3 宫内只能出现一次。
注意:
-
空白格用
'.'表示; -
一个有效的数独不一定是可解的,只需要验证已经填入的数字是否有效即可。
示例 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"]]
输出:true
示例 2:
输入:
board =
[["8","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"]]
输出:false
解释:左上角 3×3 宫格内有两个 '8',因此无效。
解题思路
本题的核心是 检查三种约束条件:
-
每行数字不能重复;
-
每列数字不能重复;
-
每个 3×3 宫格内数字不能重复。
方法
-
使用三个二维数组来记录数字是否出现过:
-
row[9][9]:行出现记录 -
col[9][9]:列出现记录 -
box[9][9]:3×3 宫格出现记录
-
-
遍历整个棋盘:
-
如果当前格是
'.',跳过; -
否则将字符转为数字索引
num = board[i][j] - '1'; -
计算当前格所属的宫格索引
boxIndex = (i / 3) * 3 + j / 3; -
如果
row[i][num]、col[j][num]或box[boxIndex][num]已经标记过,则返回false; -
否则将其标记为已出现。
-
-
遍历完成后仍未发现冲突,则数独有效,返回
true。
C语言实现
#include <stdbool.h>
bool isValidSudoku(char** board, int boardSize, int* boardColSize) {
int row[9][9] = {0};
int col[9][9] = {0};
int box[9][9] = {0};
for(int i = 0; i < 9; i++){
for(int j = 0; j < 9; j++){
if(board[i][j] == '.') continue;
int num = board[i][j] - '1'; // 数字转换为索引 0~8
int boxIndex = (i / 3) * 3 + j / 3; // 计算 3x3 宫格索引
if(row[i][num] || col[j][num] || box[boxIndex][num])
return false;
row[i][num] = 1;
col[j][num] = 1;
box[boxIndex][num] = 1;
}
}
return true;
}
算法分析
-
时间复杂度:O(9×9) = O(1),固定大小棋盘,遍历每个格子一次;
-
空间复杂度:O(9×9) = O(1),使用固定大小的三个二维数组存储状态。
总结
本题属于 经典的状态记录题,核心技巧是:
-
使用辅助数组记录行、列、宫格的状态;
-
宫格索引计算公式:
boxIndex = (i/3)*3 + j/3; -
遇到 '.' 跳过即可。
面试时,如果能讲出这一思路,并且写出简洁的 C 语言实现,基本可以轻松通过。