问题:
编写一个程序,解决数独问题。
一个数独的解法需遵循如下规则:
-
数字 1-9 在每一行只能出现一次。
-
数字 1-9 在每一列只能出现一次。
-
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
空白格用 ‘.’ 表示,比如一个数独的题目为:[[“5”,“3”,".",".",“7”,".",".",".","."],[“6”,".",".",“1”,“9”,“5”,".",".","."],[".",“9”,“8”,".",".",".",".",“6”,"."],[“8”,".",".",".",“6”,".",".",".",“3”],[“4”,".",".",“8”,".",“3”,".",".",“1”],[“7”,".",".",".",“2”,".",".",".",“6”],[".",“6”,".",".",".",".",“2”,“8”,"."],[".",".",".",“4”,“1”,“9”,".",".",“5”],[".",".",".",".",“8”,".",".",“7”,“9”]]
数独的解:
[[“5”,“3”,“4”,“6”,“7”,“8”,“9”,“1”,“2”],[“6”,“7”,“2”,“1”,“9”,“5”,“3”,“4”,“8”],[“1”,“9”,“8”,“3”,“4”,“2”,“5”,“6”,“7”],[“8”,“5”,“9”,“7”,“6”,“1”,“4”,“2”,“3”],[“4”,“2”,“6”,“8”,“5”,“3”,“7”,“9”,“1”],[“7”,“1”,“3”,“9”,“2”,“4”,“8”,“5”,“6”],[“9”,“6”,“1”,“5”,“3”,“7”,“2”,“8”,“4”],[“2”,“8”,“7”,“4”,“1”,“9”,“6”,“3”,“5”],[“3”,“4”,“5”,“2”,“8”,“6”,“1”,“7”,“9”]]
答案被标成红色。
Note:
给定的数独序列只包含数字 1-9 和字符 ‘.’ 。
你可以假设给定的数独只有唯一解。
给定数独永远是 9x9 形式的。
算法
class Solution {
private boolean isEnd = false;
public void solveSudoku(char[][] board) {
dfs(board, 0, -1);
}
/*
* 返回是否正确
*/
private boolean dfs(char[][] board, int x, int y){
//结束条件
if(isEnd){
return true;
}
//不合法直接返回
if(!isValid(board, x, y)){
return false;
}
//是否找到最后一个了
if(x == 8 && y == 8){
isEnd = true;
return true;
}
//递归
int[] pos = getNextPos(x, y);
int nx = pos[0], ny = pos[1];
if(board[nx][ny] == '.'){
for(int i = 1; i <= 9; i++){
board[nx][ny] = (char)('0' + i);
if(dfs(board, nx, ny)){
//除非找到一个解,否则都是返回false
return true;
}
board[nx][ny] = '.';
}
}else{
if(dfs(board, nx, ny)){
//除非找到一个解,否则都是返回false
return true;
}
}
return false;
}
/*
* 确认位置x, y放的数据是否对
*/
private boolean isValid(char[][] board, int x, int y){
if(x == 0 && y == -1){
return true;
}
//行
boolean[] row = new boolean[10];
for(int i = 0; i < 9; i++){
if(board[x][i] == '.'){
continue;
}
int val = board[x][i] - '0';
if(row[val]){
return false;
}
row[val] = true;
}
//列
boolean[] col = new boolean[10];
for(int i = 0; i < 9; i++){
if(board[i][y] == '.'){
continue;
}
int val = board[i][y] - '0';
if(col[val]){
return false;
}
col[val] = true;
}
//宫格
int nr = x / 3;
int nc = y / 3;
boolean[] gg = new boolean[10];
for(int i = 3 * nr; i < 3 * nr + 3; i++){
for(int j = 3 * nc; j < 3 * nc + 3; j++){
if(board[i][j] == '.'){
continue;
}
int val = board[i][j] - '0';
if(gg[val]){
return false;
}
gg[val] = true;
}
}
return true;
}
/*
* 从上到下,从左到右依次获取下一个位置
*/
private int[] getNextPos(int x, int y){
if(y == 8){
return new int[]{
x + 1, 0};
}else{
return new int[]{
x, y + 1};
}
}
}
问题参考:
- https://leetcode-cn.com/problems/sudoku-solver/