问题描述:
请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。
1.数字 1-9 在每一行只能出现一次。
2.数字 1-9 在每一列只能出现一次。
3.数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
链接:https://leetcode.cn/leetbook/read/top-interview-questions-easy/x2f9gg/
来源:力扣(LeetCode)
解法一:暴力解法
思路:遍历每一个元素,判断它位于哪一宫,哪一行,哪一列。在其所在宫,行,列内查重
bool isValidSudoku(char** board, int boardSize, int* boardColSize){
int i, j, k, l, rowMax, rowMin, colMax, colMin;
//双重for循环遍历每一个元素
for(i = 0; i < 9; i++){
for(j = 0; j < 9; j++){
//找到非空元素
if(board[i][j] != '.'){
//判断元素所在宫
if(i <= 2){
colMin = 0;
colMax = 2;
}else if(i >= 6){
colMin = 6;
colMax = 8;
}else{
colMin = 3;
colMax = 5;
}
if(j <= 2){
rowMin = 0;
rowMax = 2;
}else if(j >= 6){
rowMin = 6;
rowMax = 8;
}else{
rowMin = 3;
rowMax = 5;
}
//宫内循环查重
for(k = colMin; k <= colMax; k++){
for(l = rowMin; l <= rowMax; l++){
if((k != i || l != j) && board[k][l] == board[i][j]) return false;
}
}
//同列循环查重
for(k = i + 1; k < 9; k++){
if(board[k][j] == board[i][j]) return false;
}
//同行循环查重
for(k = j + 1; k < 9; k++){
if(board[i][k] == board[i][j]) return false;
}
}
}
}
return true;
}
解法二:哈希表
思路:遍历二维数组,对于每一个非空元素:若哈希表不存在此元素,则向哈希表中添加此元素作为key,其两个下标组成一个数组作为value;若其在哈希表中已经存在,判断两个相同元素的位置关系,同行/同列/同宫则返回false(这里判断同行同列同宫直接用两元素的横纵下标分别相减取绝对值,判断是否 = 0 或同时 <= 2 即可)。
可惜的是,这个数组我始终没法把它存到哈希表里。其实还有一个想法,把元素下标拼接成字符串存进去,用的时候再字符串分割。
解法三:三个二维数组
思路:运用二维数组的每一个位置的横纵下标作为信息记录载体,而该位置的元素值作为标志。具体见代码。
bool isValidSudoku(char** board, int boardSize, int* boardColSize){
//创建三个二维数组分别用来保存某一行,列,宫存在非空元素信息
int row[9][9] = {0}, column[9][9] = {0}, area[9][9] = {0};
int i, j, num, areaInd;
for(i = 0; i < 9; i++){
for(j = 0; j < 9; j++){
//操作非空数据
if(board[i][j] != '.'){
//类型转换,且需要-1作为下标
num = board[i][j] - '0' - 1;
//计算元素所在宫
areaInd = i / 3 * 3 + j / 3;
//同行,同列,同宫且同值判断
if(row[i][num] == 1 || column[j][num] == 1 || area[areaInd][num] == 1) return false;
//不存在上述三种相同情况,则存入
row[i][num] = 1;
column[j][num] = 1;
area[areaInd][num] = 1;
}
}
}
return true;
}
总结:解法三这种利用二维数组的横纵坐标记录信息的思想很好,值得反复品味。