偷了个懒,把解释都放到注释里面了。
js 代码:
var n = 9; // 这个表示数独的规模
function getArr(){
return [0,0,0,0,0,0,0,0,0,0];
}
function checkRowAndRol(board) {
for (var i = 0; i < n; i++) {
var arr = getArr();
for (var j = 0; j < n; j++) {
if(arr[board[i][j]] != 0)
return false;
arr[board[i][j]] = 1;
}
var arr = getArr();
for (var j = 0; j < n; j++) {
if(arr[board[j][i]] != 0)
return false;
arr[board[j][i]] = 1;
}
}
return true;
}
function doneOrNot(board) {
if(!checkRowAndRol(board)) return "try again!";
for( var i = 0; i < n; i++){
for( var j = 0; j < n; j++){
if(!checkNine(board , i , j)) return "try again!";
}
}
return "Finished!";
}
function checkNine(board , heigth , weidth){
h = Math.floor(weidth / 3);
w = Math.floor(heigth / 3);
//除以3,计算出当前位置处于第几个九宫格
//乘以3,计算出当前九宫格开始的位置
//加3,得到当前九宫格终止位置
for(var i = w * 3; i < w * 3 + 3; i++){
for(var j = h * 3; j < h * 3 + 3; j++){
if(i == heigth && j == weidth) continue;
if(board[i][j] == board[heigth][weidth]) return false;
}
}
return true;
}
今天在codewars 上刷题,看到了判断数独解法是否正确的题,于是尝试了一种新写法:
Java 代码
public class SudokuValidator {
public static boolean check(int[][] sudoku) {
int [][] flag = new int[3][3];
for(int i = 0 ; i < sudoku.length ; i++){
int flag1 = 0,flag2 = 0;
for(int j = 0;j<sudoku[i].length;j++){
flag1 ^= (1 << sudoku[i][j]);
flag2 ^= (1 << sudoku[j][i]);
flag[i/3][j/3] ^= (1 << sudoku[i][j]);
}
if (flag1 != 0x3FE || flag2 != 0x3FE) return false;
}
for(int i = 0; i < 3;i++)
for(int j = 0; j< 3;j++)
if (flag[i][j] != 0x3FE) return false;
return true;
}
}
效率比之前的代码高出不少。
解释下思路:
1.数独要满足三种情况中不能有重复的数字,这些数字是 1 到 9 之间的整数。
2.每一种情况一共有九个计算项(九行,九列,九个九宫格)。
3.每个计算项用一个变量保存是否有重复。
4.利用异或运算的性质( 1 ^ 1 == 0 , 1 ^ 0 == 1 )来判断是否重复。
5.行和列复用了同两个变量来计算。
6.九宫格没有想到复用变量的方法,于是开了一个二维数组:
利用 i / 3 , j / 3 来计算当前元素是属于哪一个九宫格的,然后计算对应位置的值
7.最后判断 每一个计算项的计算结果是不是 1111111110(二进制) 也就是 0xFE ,如果不是,那对应情况的对应项一定有重复的数字。