https://leetcode.com/problems/sudoku-solver/
A sudoku puzzle...
...and its solution numbers marked in red.
https://www.programcreek.com/2014/05/leetcode-sudoku-solver-java/
http://blog.csdn.net/linhuanmars/article/details/20748761
Write a program to solve a Sudoku puzzle by filling the empty cells.
A sudoku solution must satisfy all of the following rules:
- Each of the digits
1-9
must occur exactly once in each row. - Each of the digits
1-9
must occur exactly once in each column. - Each of the the digits
1-9
must occur exactly once in each of the 93x3
sub-boxes of the grid.
Empty cells are indicated by the character
'.'
.A sudoku puzzle...
...and its solution numbers marked in red.
Note:
- The given board contain only digits
1-9
and the character'.'
. - You may assume that the given Sudoku puzzle will have a single unique solution.
- The given board size is always
9x9
public void solveSudoku(char[][] board) {
if(board == null || board.length == 0)
return;
solve(board);
}
public boolean solve(char[][] board){
for(int i = 0; i < board.length; i++){
for(int j = 0; j < board[0].length; j++){
if(board[i][j] == '.'){
for(char c = '1'; c <= '9'; c++){//trial. Try 1 through 9
if(isValid(board, i, j, c)){
board[i][j] = c; //Put c for this cell
if(solve(board))
return true; //If it's the solution return true
else
board[i][j] = '.'; //Otherwise go back
}
}
return false;
}
}
}
return true;
}
private boolean isValid(char[][] board, int row, int col, char c){
for(int i = 0; i < 9; i++) {
if(board[i][col] != '.' && board[i][col] == c) return false; //check row
if(board[row][i] != '.' && board[row][i] == c) return false; //check column
if(board[3 * (row / 3) + i / 3][ 3 * (col / 3) + i % 3] != '.' &&
board[3 * (row / 3) + i / 3][3 * (col / 3) + i % 3] == c) return false; //check 3*3 block
}
return true;
}
http://www.cnblogs.com/grandyang/p/4421852.htmlhttps://www.programcreek.com/2014/05/leetcode-sudoku-solver-java/
bool isValid(vector<vector<char> > &board, int i, int j) { for (int col = 0; col < 9; ++col) { if (col != j && board[i][j] == board[i][col]) return false; } for (int row = 0; row < 9; ++row) { if (row != i && board[i][j] == board[row][j]) return false; } for (int row = i / 3 * 3; row < i / 3 * 3 + 3; ++row) { for (int col = j / 3 * 3; col < j / 3 * 3 + 3; ++col) { if ((row != i || col != j) && board[i][j] == board[row][col]) return false; } } return true; }
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.
这道题的方法就是用在N-Queens中介绍的常见套路。简单地说思路就是循环处理子问题,对于每个格子,带入不同的9个数,然后判合法,如果成立就递归继续,结束后把数字设回空。大家可以看出代码结构和N-Queens是完全一样的。判合法可以用Valid Sudoku做为subroutine,但是其实在这里因为每次进入时已经保证之前的board不会冲突,所以不需要判断整个盘,只需要看当前加入的数字和之前是否冲突就可以,这样可以大大提高运行效率,毕竟判合法在程序中被多次调用。
public void solveSudoku(char[][] board) { if(board == null || board.length != 9 || board[0].length !=9) return; helper(board,0,0); } private boolean helper(char[][] board, int i, int j) { if(j>=9) return helper(board,i+1,0); if(i==9) { return true; } if(board[i][j]=='.') { for(int k=1;k<=9;k++) { board[i][j] = (char)(k+'0'); if(isValid(board,i,j)) { if(helper(board,i,j+1)) return true; } board[i][j] = '.'; } } else { return helper(board,i,j+1); } return false; } private boolean isValid(char[][] board, int i, int j) { for(int k=0;k<9;k++) { if(k!=j && board[i][k]==board[i][j]) return false; } for(int k=0;k<9;k++) { if(k!=i && board[k][j]==board[i][j]) return false; } for(int row = i/3*3; row<i/3*3+3; row++) { for(int col=j/3*3; col<j/3*3+3; col++) { if((row!=i || col!=j) && board[row][col]==board[i][j]) return false; } } return true; }
X. http://codesniper.blogspot.com/2015/03/37-sudoku-solver-leetcode.html
X. Inefficient?
https://discuss.leetcode.com/topic/11327/straight-forward-java-solution-using-backtracking
http://blog.csdn.net/zdavb/article/details/48165059
http://www.cnblogs.com/springfor/p/3884252.html
void solveSudoku(vector<vector<char>>& board) { dfs(board, 0); } bool dfs(vector<vector<char>>& board, const int pos) { if (pos == 81) { return true; } int x = pos / 9, y = pos % 9; if (board[x][y] != '.') { return dfs(board, pos + 1); } for (char i = '0'; i <= '9'; ++i) { board[x][y] = i; if (isValidSudoku(board) && dfs(board, pos + 1)) return true; } board[x][y] = '.'; return false; } bool isValidSudoku(vector<vector<char>>& board) { int col[9][9] = {0}, row[9][9] = {0}, rec[9][9] = {0}; for(int i = 0; i < 9; ++ i) { for(int j = 0; j < 9; ++ j) { if(board[i][j] != '.') { int num = board[i][j] - '0' - 1, k = i / 3 * 3 + j / 3; if(col[i][num] || row[j][num] || rec[k][num]) return false; col[i][num] = row[j][num] = rec[k][num] = 1; } } } return true; }
http://blog.csdn.net/u011095253/article/details/9158497
Recursively fill the empty cell with available number that make the sudouku board valid, if all numbers were not valid in this cell, backtrack to last cell and iteratively try next number until all cells are filled with number.
This is a kind of standard solution for all recursion problem. 1.Find the base case or terminating case.Usually was written in the fist line of the recursion function(if(...) ...return) 2. Iteratively try valid one and go to next cell, if the current trial doesn't work, reset the current trial to original value and try next possibility. So the code always looks like :
setValue(i) / addItem(i);
helper(...,i+1);
setValue(original)/removeItem(i);
public void solveSudoku(char[][] board) {
if(board==null || board.length==0 || board[0].length==0) return;
boolean[][] row= new boolean[9][9];
boolean[][] col= new boolean[9][9];
boolean[][] block=new boolean[9][9];
for(int i=0;i<board.length;i++){
for(int j=0;j<board[0].length;j++){
if(board[i][j]<='9' && board[i][j]>='1'){
int num=board[i][j]-'1';
int bnum=(i/3)*3+j/3;
if(row[i][num] || col[j][num] || block[bnum][num]) return;
row[i][num] = col[j][num] = block[bnum][num] =true;
}
}
}
helper(board,0,row,col,block);
}
public boolean helper(char[][] board, int ind, boolean[][] row, boolean[][] col, boolean[][] block){
if(ind==81) return true;
int i=ind/9;
int j=ind%9;
int b=(i/3)*3+j/3;
if(board[i][j]=='.'){
for(int k=1;k<=9;k++){
if((!row[i][k-1]) && (!col[j][k-1]) && (!block[b][k-1])){
board[i][j]=(char)('0'+k);
row[i][k-1] =col[j][k-1] =block[b][k-1]=true;
if (helper(board,ind+1,row,col,block)) return true;
else {
row[i][k-1] =col[j][k-1] =block[b][k-1]=false;
board[i][j]='.';
}
}
}
return false;
}
else return helper(board,ind+1,row,col,block);
}
X. Inefficient?
https://discuss.leetcode.com/topic/11327/straight-forward-java-solution-using-backtracking
Try 1 through 9 for each cell. The time complexity should be 9 ^ m (m represents the number of blanks to be filled in), since each blank can have 9 choices. Details see comments inside code. Let me know your suggestions.
public void solveSudoku(char[][] board) {
if(board == null || board.length == 0)
return;
solve(board);
}
public boolean solve(char[][] board){
for(int i = 0; i < board.length; i++){
for(int j = 0; j < board[0].length; j++){
if(board[i][j] == '.'){
for(char c = '1'; c <= '9'; c++){//trial. Try 1 through 9
if(isValid(board, i, j, c)){
board[i][j] = c; //Put c for this cell
if(solve(board))
return true; //If it's the solution return true
else
board[i][j] = '.'; //Otherwise go back
}
}
return false;
}
}
}
return true;
}
private boolean isValid(char[][] board, int row, int col, char c){
for(int i = 0; i < 9; i++) {
if(board[i][col] != '.' && board[i][col] == c) return false; //check row
if(board[row][i] != '.' && board[row][i] == c) return false; //check column
if(board[3 * (row / 3) + i / 3][ 3 * (col / 3) + i % 3] != '.' &&
board[3 * (row / 3) + i / 3][3 * (col / 3) + i % 3] == c) return false; //check 3*3 block
}
return true;
}
这道题使用的是回溯算法,回溯本质是深搜+剪枝。深搜又常常利用递归,然后当替换每个“.”时都判断是否有效。如果有效的话,就继续递归下去。
注意,一般递归函数都在开头位置判断是否结束,但是对于该问题而言,不大容易判断叶节点。所以这里采用的是利用返回值true或false来对树的深度进行控制。如果为solve到false时,就回溯。回溯的手段就是使用更改函数主体复位,并return
http://www.jiuzhang.com/solutions/sudoku-solver/http://www.cnblogs.com/springfor/p/3884252.html
public void solveSudoku(char[][] board){ solve(board); } public boolean solve(char[][] board) { for(int i = 0; i < 9; i++) { for(int j = 0; j < 9; j++){ if(board[i][j] != '.'){ continue; } for(int k = 1; k <= 9; k++){ board[i][j] = (char) (k + '0'); // set value if (isValid(board, i, j) && solve(board)){ return true; } board[i][j] = '.';// backtrack } return false;//\\ } } return true;//\\ } public boolean isValid(char[][] board, int a, int b){ Set<Character> contained = new HashSet<Character>(); for(int j=0;j<9;j++){ if(contained.contains(board[a][j])) return false; if(board[a][j]>'0' && board[a][j]<='9') contained.add(board[a][j]); } contained = new HashSet<Character>(); // or call set.clear() for(int j=0;j<9;j++){ if (contained.contains(board[j][b])) { return false; } if (board[j][b]>'0' && board[j][b]<='9') { contained.add(board[j][b]); } } contained = new HashSet<Character>(); for (int m = 0; m < 3; m++) { for (int n = 0; n < 3; n++){ int x = a / 3 * 3 + m, y = b / 3 * 3 + n; if (contained.contains(board[x][y])) { return false; } if (board[x][y] > '0' && board[x][y] <= '9') { contained.add(board[x][y]); } } } return true; }http://cs-cjl.com/2016/09_29_leetcode_37_sudoku_solver
void solveSudoku(vector<vector<char>>& board) { dfs(board, 0); } bool dfs(vector<vector<char>>& board, const int pos) { if (pos == 81) { return true; } int x = pos / 9, y = pos % 9; if (board[x][y] != '.') { return dfs(board, pos + 1); } for (char i = '0'; i <= '9'; ++i) { board[x][y] = i; if (isValidSudoku(board) && dfs(board, pos + 1)) return true; } board[x][y] = '.'; return false; } bool isValidSudoku(vector<vector<char>>& board) { int col[9][9] = {0}, row[9][9] = {0}, rec[9][9] = {0}; for(int i = 0; i < 9; ++ i) { for(int j = 0; j < 9; ++ j) { if(board[i][j] != '.') { int num = board[i][j] - '0' - 1, k = i / 3 * 3 + j / 3; if(col[i][num] || row[j][num] || rec[k][num]) return false; col[i][num] = row[j][num] = rec[k][num] = 1; } } } return true; }
http://blog.csdn.net/u011095253/article/details/9158497
public boolean isValid(int v, int row, int col, char[][] board){ for(int i=0;i<9;i++){ if(board[row][i] - '0'==v) return false; if(board[i][col] - '0'==v) return false; int row_s = 3*(row/3) + i/3; int col_s = 3*(col/3) + i%3; if(board[row_s][col_s] - '0'==v) return false; } return true; }
http://huangyawu.com/leetcode-sudoku-solver-java/
https://leetcode.com/discuss/30482/straight-forward-java-solution-using-backtracking
Backtracking algorithms generally have exponential worst-case running time. However, the efficient pruning
public void solveSudoku(char[][] board) {
if(board == null || board.length == 0)
return;
solve(board);
}
public boolean solve(char[][] board){
for(int i = 0; i < board.length; i++){
for(int j = 0; j < board[0].length; j++){
if(board[i][j] == '.'){
for(char c = '1'; c <= '9'; c++){//trial. Try 1 through 9 for each cell
if(isValid(board, i, j, c)){
board[i][j] = c; //Put c for this cell
if(solve(board))
return true; //If it's the solution return true
else
board[i][j] = '.'; //Otherwise go back
}
}
return false;
}
}
}
return true;
}
public boolean isValid(char[][] board, int i, int j, char c){
//Check colum
for(int row = 0; row < 9; row++)
if(board[row][j] == c)
return false;
//Check row
for(int col = 0; col < 9; col++)
if(board[i][col] == c)
return false;
//Check 3 x 3 block
for(int row = (i / 3) * 3; row < (i / 3) * 3 + 3; row++)
for(int col = (j / 3) * 3; col < (j / 3) * 3 + 3; col++)
if(board[row][col] == c)
return false;
return true;
}
https://leetcode.com/discuss/51308/two-very-simple-and-neat-java-dfs-backtracking-solutions
https://leetcode.com/discuss/7086/there-is-a-dancing-links-x-algorithm
private
boolean
isValid(
char
[][] board,
int
row,
int
col){
for
(
int
i=
0
; i<
9
; i++){
if
(i!=row && board[i][col] == board[row][col])
return
false
;
if
(i!=col && board[row][i] == board[row][col])
return
false
;
}
int
r = row /
3
*
3
;
int
c = col /
3
*
3
;
for
(
int
i=
0
; i<
3
; i++)
for
(
int
j=
0
; j<
3
; j++){
if
(r + i != row && c + j != col
&& board[r+i][c+j] == board[row][col])
return
false
;
}
return
true
;
}
Backtracking algorithms generally have exponential worst-case running time. However, the efficient pruning
isValid
makes it fast enough in practice :-)public void solveSudoku(char[][] board) {
if(board == null || board.length == 0)
return;
solve(board);
}
public boolean solve(char[][] board){
for(int i = 0; i < board.length; i++){
for(int j = 0; j < board[0].length; j++){
if(board[i][j] == '.'){
for(char c = '1'; c <= '9'; c++){//trial. Try 1 through 9 for each cell
if(isValid(board, i, j, c)){
board[i][j] = c; //Put c for this cell
if(solve(board))
return true; //If it's the solution return true
else
board[i][j] = '.'; //Otherwise go back
}
}
return false;
}
}
}
return true;
}
public boolean isValid(char[][] board, int i, int j, char c){
//Check colum
for(int row = 0; row < 9; row++)
if(board[row][j] == c)
return false;
//Check row
for(int col = 0; col < 9; col++)
if(board[i][col] == c)
return false;
//Check 3 x 3 block
for(int row = (i / 3) * 3; row < (i / 3) * 3 + 3; row++)
for(int col = (j / 3) * 3; col < (j / 3) * 3 + 3; col++)
if(board[row][col] == c)
return false;
return true;
}
https://leetcode.com/discuss/51308/two-very-simple-and-neat-java-dfs-backtracking-solutions
https://leetcode.com/discuss/7086/there-is-a-dancing-links-x-algorithm
Dr. Donald Knuth’s Dancing Links Algorithm solves an Exact Cover situation. The Exact Cover problem can be extended to a variety of applications that need to fill constraints. Sudoku is one such special case of the Exact Cover problem.
NOTE:This is a very complicate solution.
http://huntfor.iteye.com/blog/2087778
DFS在找到一个结果的时候会继续回溯寻找下一个可能的结果,因此我又设置了一个全局变量来添加控制。这无疑让代码可读性变差
// only check condition(over) at first, no need check condition before every recursive call.
Determine whether a Sudoku has a unique solution
// only check condition(over) at first, no need check condition before every recursive call.
Determine whether a Sudoku has a unique solution
If you return a number instead of a boolean, you can destinguish between cases where there are 0, 1, or more than 1 solution(s).
To return all solutions: clone the matrix, and put it into list.