原题目链接:解数独
1. Leetcode官方题解用的是先行后列顺序遍历元素进行遍历,是一种固定的遍历模式,对于某些情况需要花费较多非必要时间,没有充分利用各元素之间的影响。比如在某个位置填入一个数字之后,与它间隔较远的一个位置就只剩一个选择或没有选择了,我们可以直接处理该位置,可以减少对于两位置之间的一些判断。
2. 本算法的思想是对于每个当前二维数独数组,生成一个优先队列,优先队列的元素为每个待填入位置行和列及该位置可填入数字的个数size,优先队列的顺序为size小的在前。然后每次从优先队列里面选择最小size位置进行遍历,直到找到一种答案或者无解。
3. 具体实现的代码如下:
class Solution {
public void solveSudoku(char[][] board) {
PriorityQueue<ChooseNode> PrioQ = getPrioQ(board);
solve(board,PrioQ);
}
public boolean solve(char[][] board,PriorityQueue<ChooseNode> PrioQ){
if(PrioQ.size() == 0){
return true;
}
ChooseNode curchooseNode = PrioQ.poll();
int row = curchooseNode.row;
int col = curchooseNode.col;
if(curchooseNode.size == 0){
return false;
}
for(int i=1;i<=9;++i){
if(check(board,row,col,(char)(i + '0'))){
board[row][col] = (char)(i + '0');
PriorityQueue<ChooseNode> newPrioQ = getPrioQ(board);
if(solve(board,newPrioQ)){
return true;
}
}
}
board[row][col] = '.';
return false;
}
public static boolean check(char[][] board,int row,int col,char c){
for(int k=0;k<9;++k){
if(k != col && board[row][k] == c){
return false;
}
if(k != row && board[k][col] == c){
return false;
}
}
for(int i=(row / 3) * 3;i < (row / 3) * 3 + 3;++i){
for(int j=(col / 3) * 3;j < (col / 3) * 3 + 3;++j){
if((i != row || j != col) && board[i][j] == c){
return false;
}
}
}
return true;
}
public static PriorityQueue<ChooseNode> getPrioQ(char[][] board){
PriorityQueue<ChooseNode> newPrioQ = new PriorityQueue<ChooseNode>(new Comparator<ChooseNode>(){
public int compare(ChooseNode a,ChooseNode b){
return a.size - b.size;
}
});
for(int i = 0;i < 9;++i){
for(int j = 0;j < 9;++j){
if(board[i][j] == '.'){
ChooseNode newNode = new ChooseNode();
int size = 0;
for(int k=1;k <= 9;++k){
if(check(board,i,j,(char)(k+48))){
size++;
}
}
newNode.row = i;
newNode.col = j;
newNode.size = size;
newPrioQ.offer(newNode);
}
}
}
return newPrioQ;
}
}
class ChooseNode{
int size = 0;
int row;
int col;
}
4. 改进后对于有解的数独时间明显减少,对于无解情况和改进前差不多。