Write a program to solve a Sudoku puzzle by filling the empty cells.
Empty cells are indicated by the character ‘.’.
You may assume that there will be only one unique solution.
A sudoku puzzle…
…and its solution numbers marked in red.
JAVA
方法一
直接使用递归暴力解题,一开始以为会超时,没想到不但AC了,而且效率在前1/5,只需要注意好边界条件即可。
第一次在编译器上跑的时候,由于偷懒,在判断数字是否用过时,在一个循环中同时判断横竖两个方向,导致判断不全,如下
for (int i = 0; i < MAXSIZE; i++) {
if (board[row][i] == '.') {
continue;
} else {
used[board[row][i] - '0'] = true;
}
if (board[i][column] == '.'){
continue;
}
else {
used[board[i][column] - '0'] = true;
}
}
在这种情况下,当横向判断执行了continue时,就不会判断纵向了,导致可用数字的范围扩大。所以偷懒不能太过分。。。
在本地测试的时候,为了找错,写了输出语句,同时将sysout重定向到本地文件中,方便查找问题。在下列代码中已经注释掉输出部分。
public class Solution {
static int MAXSIZE = 9;
static int SUBBOXSIZE = 3;
public void solveSudoku(char[][] board) {
if (board.length != MAXSIZE || board[0].length != MAXSIZE){
return ;
}
fillBoard(board,0,0);
// for (int i = 0; i < MAXSIZE; i++) {
// for (int j = 0; j < MAXSIZE; j++) {
// System.out.print(board[i][j] + " ");
// }
// System.out.println();
// }
}
public boolean fillBoard(char[][] board,int startRow, int startCloumn){
if (startRow == MAXSIZE && startCloumn == MAXSIZE) {
return true;
}
// 找第一个需要填数字的空格
int row = startRow;
int column = startCloumn;
boolean findEmptyCell = false;
while (row < MAXSIZE) {
while (column < MAXSIZE) {
if (board[row][column] == '.') {
findEmptyCell = true;
break;
} else {
++column;
}
}
if (findEmptyCell) {
break;
} else {
++row;
column = 0;
}
}
if (!findEmptyCell) {
return true;
}
// 找出在该空格可填写的数字有哪些,若有重复数字说明已经不满足数独条件
// uesd设置为10可以使下标与数独中的数字一一对应
boolean [] used = new boolean[10];
for (int i = 0; i < MAXSIZE; i++) {
if (board[row][i] == '.') {
continue;
} else {
used[board[row][i] - '0'] = true;
}
}
for (int i = 0; i < MAXSIZE; i++) {
if (board[i][column] == '.'){
continue;
}
else {
used[board[i][column] - '0'] = true;
}
}
// 获取subbox的左上角坐标
int subBoxRow = row / 3 * 3;
int cubBoxColmun = column / 3 * 3;
for (int i = 0; i < 3; ++i){
for (int j = 0; j < 3; j++) {
if (board[subBoxRow + i][cubBoxColmun + j] == '.'){
continue;
}
else {
used[board[subBoxRow + i][cubBoxColmun + j] - '0'] = true;
}
}
}
// 填写未使用的数字并递归判断,因为下一层可以填写的数字范围会重新计算,所以对于本次填写不符合条件的数字,不需要重新设置为false
for (int i = 1; i <= MAXSIZE ; i++) {
if(used[i]) {
continue;
}else {
board[row][column] = (char)( '0' + i);
// System.out.println("row = " + row + "\tcolumn = " + column);
// for (int k = 0; k < MAXSIZE; k++) {
// for (int j = 0; j < MAXSIZE; j++) {
// System.out.print(board[k][j] + " ");
// }
// System.out.println();
// }
// System.out.println();
// System.out.println();
if (fillBoard(board,row,column)){
return true;
}
}
}
board[row][column] = '.';
return false;
}
}