问题:
请你判断一个 9x9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。
1、数字 1-9 在每一行只能出现一次。
2、数字 1-9 在每一列只能出现一次。
3、数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)
数独部分空格内已填入了数字,空白格用 '.' 表示。
示例:
输入: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
解答:
大致思路为:首先定义三种容器,分别记录对应的行、列、3*3宫格出现过哪些数字;接着遍历一次整个数独,在这过程中,每遍历一个元素,就根据其位置坐标在对应的行、列、3*3宫格的对应数字的位置作标记,同时检查是否此位置是否之前已有过标记,若有则返回false,若无则继续循环。
若用 i 表示行,j 表示列,则k = (i / 3) * 3 + j / 3表示3*3宫格。
具体实现的容器可分为哈希表、二维数组、一维数组的二进制位,代码实现如下:
1、哈希表
以数独中出现的数作为key,若能在哈希表中找到此key对应的元素,则说明此元素已在该行(列、3*3宫格)存在;若不能在会自动添加该key对应的元素。
bool isValidSudoku(vector<vector<char>>& board)
{
unordered_map<int, int> rows[9];
unordered_map<int, int> columns[9];
unordered_map<int, int> cells[9];
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
char c = board[i][j];
if (c == '.')
continue;
int t = c - '0';
int k = (i / 3) * 3 + j / 3;
if (rows[i][t] || columns[j][t] || cells[k][t])
return false;
rows[i][t]++;
columns[j][t]++;
cells[k][t]++;
}
}
return true;
}
2、二维数组
line[i][num]就表示第 i 行是否存在数字num,若有则line[i][num]为1,若没有则为0。其余类似。
bool isValidSudoku(vector<vector<char>>& board)
{
int line[9][9] = {0};
int column[9][9] = {0};
int cell[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] - '0' - 1;
int k = i / 3 * 3 + j / 3;
if (line[i][num] != 0 || column[j][num] != 0 || cell[k][num] != 0)
return false;
line[i][num] = column[j][num] = cell[k][num] = 1;
}
return true;
}
3、一维数组的二进制位
line[i]就表示第 i 行的数字分布情况,由于它的元素类型为int,是32bit的二进制数字,可用后9位数来表示数字的分布情况。然后用位运算来判断和更新数字分布情况。
bool isValidSudoku(vector<vector<char>>& board)
{
int line[9] = {0}, column[9] = {0}, cell[9] = {0};
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
char c = board[i][j];
if(c == '.')
continue;
int shift = 1 << (c - '0' - 1);
int k = i / 3 * 3 + j / 3;
if ((line[i] | shift) == line[i] || (column[j] | shift) == column[j] || (cell[k] | shift) == cell[k])
return false;
line[i] |= shift;
column[j] |= shift;
cell[k] |= shift;
}
}
return true;
}