解题思路
36. 有效的数独
题目要求判断九宫格中的任意数字在它所在行、列以及3*3宫格内只出现一次
可以使用以下三种方法解决:
- 使用哈希表HashSet、List(ArrayList和LinkedList)
- 使用boolean数组
- 使用比特进行位运算
代码
方法一:使用哈希表HashSet
//运行时间:3ms 内存消耗:38.4MB
class Solution {
public boolean isValidSudoku(char[][] board) {
//把九行、九列、九个九宫格都用Set数组表示。此外可以把Set数组换成List数组
Set<Character>[] rows = new Set[9];
Set<Character>[] cols = new Set[9];
Set<Character>[] boxes = new Set[9];
for(int i=0;i<9;i++){
rows[i] = new HashSet<>(); //如果使用List数组,那么HashSet换成ArrayList或LinkedList
cols[i] = new HashSet<>();
boxes[i] = new HashSet<>();
}
for(int row=0; row<9; row++){
for(int col=0 ; col<9; col++){
char num = board[row][col];
if(num == '.') continue;
if(rows[row].contains(num)) return false;
if(cols[col].contains(num)) return false;
int boxIndex = (row/3)*3+col/3;
if(boxes[boxIndex].contains(num)) return false;
rows[row].add(num);
cols[col].add(num);
boxes[boxIndex].add(num);
}
}
return true;
}
}
方法二:使用boolean数组
//运行时间:2ms 内存消耗:38.7MB
class Solution {
public boolean isValidSudoku(char[][] board) {
//把九行、九列、九个九宫格都用二维布尔数组表示 不需要额外初始化,默认起始值为false
boolean[][] rows = new boolean[9][9];
boolean[][] cols = new boolean[9][9];
boolean[][] boxes = new boolean[9][9];
for(int row=0; row<9; row++){
for(int col=0 ; col<9; col++){
char num = board[row][col];
if(num == '.') continue;
num = (char)(num-'1'); //eg:5放到rows[row][4]、cols[col][4]、boxes[boxIndex][4]
if(rows[row][num]) return false;
if(cols[col][num]) return false;
int boxIndex = (row/3)*3+col/3;
if(boxes[boxIndex][num]) return false;
rows[row][num] = true;
cols[col][num] = true;
boxes[boxIndex][num] = true;
}
}
return true;
}
}
方法三:使用比特进行位运算
在该方法中要注意:
Java中byte、short、char在进行运算时会自动转换为int再进行运算,它们进行运算返回的结果为int型。
①使用short类型存储9个数值,因为short类型为16个字节>9个字节,可以存储9个数值的状态:出现过为1,未出现过为0。
//运行时间:1ms 内存消耗:38.2MB
class Solution {
public boolean isValidSudoku(char[][] board) {
//把九行、九列、九个九宫格都用short类型表示,因为short类型为16个字节>9个字节
short[] rows = new short[9];
short[] cols = new short[9];
short[] boxes = new short[9];
for(int row=0; row<9; row++){
for(int col=0 ; col<9; col++){
char num = board[row][col];
if(num == '.') continue;
num = (char)(1<<(num - '1'));//int->char
if((rows[row]&num)!=0) return false;
if((cols[col]&num)!=0) return false;
int boxIndex = (row/3)*3+col/3;
if((boxes[boxIndex]&num)!=0) return false;
rows[row] = (short)(rows[row] | num); //int->short
cols[col] =(short)(cols[col] | num);
boxes[boxIndex] =(short)(boxes[boxIndex] | num) ;
}
}
return true;
}
}
②使用char类型存储9个数值,因为char类型同样为16个字节>9个字节,可以存储9个数值的状态:出现过为1,未出现过为0。
class Solution {
//运行时间:2ms 内存消耗:37.9MB
public boolean isValidSudoku(char[][] board) {
//把九行、九列、九个九宫格都用char类型表示,因为char类型为16个字节>9个字节
char[] rows = new char[9];
char[] cols = new char[9];
char[] boxes = new char[9];
for(int row=0; row<9; row++){
for(int col=0 ; col<9; col++){
char num = board[row][col];
if(num == '.') continue;
num = (char)(1<<(num - '1'));
if((rows[row]&num)!=0) return false;
if((cols[col]&num)!=0) return false;
int boxIndex = (row/3)*3+col/3;
if((boxes[boxIndex]&num)!=0) return false;
rows[row] = (char)(rows[row] | num);
cols[col] =(char)(cols[col] | num);
boxes[boxIndex] =(char)(boxes[boxIndex] | num) ;
}
}
return true;
}
}