数独问题在leetcode中有36. Valid Sudoku和37. Sudoku Solver两道,数独规则有三条:
1.每一行数字在1-9不能重复。
2.每一列数字在1-9不能重复。
3.在所属特定的3*3邻域内的数字1-9不能重复。
37. Sudoku Solver的要求是检查当前数独的合法性,采用暴力搜索对每一个格点进行检查,需要思考的是如何检查条件3的检查方法,要确定格点的3*3邻域的遍历范围也就是要确定横纵坐标的检查范围。
对于(i,j)特定的3*3邻域为(3*(i/3):3*(i/3+1),3*(j/3):y_end=3*(j/3+1)),当然在检查的时候要剔除本身格点的值
public class ValidSudoku { public static int rows; public static boolean isValid(int i,int j,char[][] board) { for(int m=0;m<rows;m++ ) { if(m!=i && board[i][j]==board[m][j]) return false; if(m!=j && board[i][j]==board[i][m]) return false; } int x_start=3*(i/3),x_end=3*(i/3+1); int y_start=3*(j/3),y_end=3*(j/3+1); for(int a=x_start;a<x_end;a++) for(int b=y_start;b<y_end;b++) { if((a==i && b==j) || board[a][b]=='.') continue; if(board[a][b]==board[i][j]) return false; } return true; } public static boolean isValidSudoku(char[][] board) { rows=board.length; for(int i=0;i<rows;i++) { for(int j=0;j<rows;j++) { if(board[i][j]=='.') continue; else { if(!isValid(i,j,board)) return false; } } } return true; }
37. Sudoku Solver的求解数独必然要依赖第一题的合法性判断,采用回溯法(递归),
基本思路:对于当前值为"."进行1-9的尝试填充,如果合法,则填充当前数值,并对下一个值为"."的格点填充(如果下一个填充一直可以进行到最后,则返回true;如果不能一直填充下去,则将当前的格点值恢复为".");如果当前格点的1-9尝试都不合法则返回false。当然最终全部填充完并合法则要返回true。代码如下:
class Solution { public static int rows; public static boolean backtrace(char[][] board) { for(int i=0;i<rows;i++) { for(int j=0;j<rows;j++) { if(board[i][j]=='.') { for(char s='1';s<='9';s++) { if(isValid(i,j,board,s)) { board[i][j]=s; if(backtrace(board)) return true; else board[i][j]='.'; } } return false; } } } return true; } public static boolean isValid(int i,int j,char[][] board,char c) { for(int m=0;m<rows;m++ ) { if(m!=i && c==board[m][j]) return false; if(m!=j && c==board[i][m]) return false; } int x_start=3*(i/3),x_end=3*(i/3+1); int y_start=3*(j/3),y_end=3*(j/3+1); for(int a=x_start;a<x_end;a++) for(int b=y_start;b<y_end;b++) { if((a==i && b==j) || board[a][b]=='.') continue; if(board[a][b]==c) return false; } return true; } public void solveSudoku(char[][] board) { rows=board.length; backtrace(board); } }