判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次
示例
输入:
[
[“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
class Solution {
public:
bool isValidSudoku(vector<vector<char>>& board) {
//利用数组作为哈希表时,由于需要多个哈希表来判断不同行列格子中数字的出现次数
//故我们可以利用一个二维数组来实现,每行或每列都用新二维数组中的行标表示,
//而新二维数组的每行我们将其视为对原数独不同行或列的哈希表,
//而用每行的a[][0~8]分别表示数字1~9的出现次数,遍历数字得到次数1,
//若之后再继续遍历数字次数不为0,则数字重复不满足数独要求。
//那么如何用于表述每个网格的出现次数呢?网格同样有9个,同样可通过对网格编号实现数组化哈希表
//让k=i/3*3+j/3得到网格编号,其中i和j代表数独的行和列
//同时大家还要注意数组从0下标开始所以作为哈希表key-value映射的时候需要让key-1.
vector<vector<int>>row(9,vector<int>(9,0));
vector<vector<int>>column(9,vector<int>(9,0));
vector<vector<int>>grid(9,vector<int>(9,0));
for(int i=0;i<9;i++){
for(int j=0;j<9;j++){
if(board[i][j]=='.')
continue;
int value = board[i][j]-'0'-1;
int k=i/3*3+j/3;
if(row[i][value]!=0||column[j][value]!=0||grid[k][value]!=0)
return false;
row[i][value]=column[j][value]=grid[k][value]=1;
}
}
return true;
}
};
注意用位存储实现哈希表的key-value,只能实现1~64个数字的存储,即记录该数字对应位然后赋值为1,例如9就可以表示为1<<9得到1000000000,即在某个位占个1便标记该数字出现过。这就是位运算作哈希表的原理,很明显只适合用于记录出现一次的情况。
class Solution {
public:
bool isValidSudoku(vector<vector<char>>& board) {
int row[9] = {0};//均表示9行9列9格,其中每个元素的位用于标记出现过的数字
int column[9] = {0};
int grid[9] = {0};
int shift = 0;
for(int i=0;i<9;i++){
for(int j=0;j<9;j++){
if(board[i][j]=='.')
continue;
int value = board[i][j]-'0';
int k = i/3*3+j/3;
shift = 1<<value;
//若出现过,则按位与结果应为原数,若要是没出现过则结果均为0,故可以用!0或者==value来判断
//注意运算的优先级,小括号一定得带上!!!
if((row[i]&shift)!=0 || (column[j]&shift)>0 || (grid[k]&shift)!=0)
return false;
row[i] |= shift;
column[j] |= shift;
grid[k] |= shift;
}
}
return true;
}
};