题目链接:Valid Sudoku有效的数独
题目已经十分确定的说了只有1~9,因此标记法无疑是非常好的选择。
基本思路:对行、列、小数独块分别用一个size为9的数组来标记数字1~9在本行(列/块)中是否已使用。
根据思路则不难写出下面的代码:
public static int startIndex = 0;
public static int sudokuSize = 9;
public boolean isValidSudoku(char[][] board) {
int i;
boolean[][] mark = new boolean[sudokuSize][sudokuSize+1];
// 判断所有行是否符合
for (i = startIndex; i < sudokuSize; i++) {
for (int j = startIndex; j < sudokuSize; j++) {
if (board[i][j] != '.') {
int temp = board[i][j] - '0';
if (mark[i][temp]) return false;
else mark[i][temp] = true;
}
}
}
// 判断所有列是否符合
initMarkArr(mark, false);
for (i = startIndex; i < sudokuSize; i++) {
for (int j = startIndex; j < sudokuSize; j++) {
if (board[j][i] != '.') {
int temp = board[j][i] - '0';
if (mark[i][temp]) return false;
else mark[i][temp] = true;
}
}
}
// 判断所有小数独块是否符合
initMarkArr(mark, false);
for (i = startIndex; i < sudokuSize; i++) {
for (int j = startIndex; j < sudokuSize; j++) {
int index = i/3 * 3 + j/3;
if (board[j][i] != '.') {
int temp = board[j][i] - '0';
if (mark[index][temp]) return false;
else mark[index][temp] = true;
}
}
}
return true;
}
// 初始化数组
public void initMarkArr(boolean[][] arr, boolean value) {
for (int j = 0; j < arr.length; j++) {
Arrays.fill(arr[j], value);
}
}
代码看起来有点冗余,我们稍作代码简化,可得如下代码
public boolean isValidSudoku(char[][] board) {
boolean[][] markRow = new boolean[9][10];
boolean[][] markCol = new boolean[9][10];
boolean[][] markBlock = new boolean[9][10];
// 多定义两个数组可以省去初始化操作
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
int index = i/3 * 3 + j/3;
if (board[j][i] != '.') {
int temp = board[j][i] - '0';
if (markRow[j][temp]) return false;
else markRow[j][temp] = true;
if (markCol[i][temp]) return false;
else markCol[i][temp] = true;
if (markBlock[index][temp]) return false;
else markBlock[index][temp] = true;
}
}
}
return true;
}
对于此题,似乎没法靠优化算法来提升效率,硬要优化的话,可以在位运算上下点功夫。
public boolean isValidSudoku(char[][] board) {
int[][] mark = new int[3][9];
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
int index = i/3 * 3 + j/3;
if (board[j][i] != '.') {
// 1左移?位,数独中最大数为9,2^8大大小于int的max
int temp = 1 << (board[j][i] - '1');
// 判断每列是否出现重复用temp,否则|上temp
if ((mark[0][j] & temp) > 0) return false;
else mark[0][j] |= temp;
// 每行
if ((mark[1][i] & temp) > 0) return false;
else mark[1][i] |= temp;
//每块
if ((mark[2][index] & temp) > 0) return false;
else mark[2][index] |= temp;
}
}
}
return true;
}
进一步简化代码
public boolean isValidSudoku(char[][] board) {
int[][] mark = new int[3][9];
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
int index = i/3 * 3 + j/3;
if (board[j][i] != '.') {
int temp = 1 << (board[j][i] - '1');
if ((mark[0][j] & temp) > 0 || (mark[1][i] & temp) > 0 || (mark[2][index] & temp) > 0) return false;
mark[0][j] |= temp;
mark[1][i] |= temp;
mark[2][index] |= temp;
}
}
}
return true;
}