题解 | #Sudoku#
Sudoku
https://www.nowcoder.com/practice/78a1a4ebe8a34c93aac006c44f6bf8a1
【Java实现】
使用回溯法,类似“N皇后”问题,具体思路和代码如下,欢迎大家交流讨论。
import java.util.*;
public class Main {
/*
一开始没什么思路,参考了题解:https://blog.nowcoder.net/n/9e0bf935707e492387116ee8c3e1c933
(其实我的解法和这个题解差别挺大的,但确实有受到启发)
思路:回溯法
(思路有点像“N皇后”问题)
总体思路:递归遍历每个空格,for循环尝试填入1-9
全局变量:
- int[][] map = new int[9][9]: 9x9的棋盘
- boolean hasFinish:是否已正确填充所有空格
- List<List<Integer>> spaces: 二维列表,存放所有空格的坐标
步骤:
1. 初始化棋盘,并记录所有空格的坐标(i,j),存至二维列表spaces中
2. 回溯函数(参数:下标index,即当前要填充的空格在spaces的下标){
终止条件:已遍历完所有空格(即index == spaces.size()),
并将hasFinish设为true
for (遍历val:1-9,作为填入空格的值) {
if (当前空格可以填入val) {
填充空格;
递归调用回溯函数(下一个空格下标:index+1);
if (hasFinish) {
return;
}
将空格值还原为0; // 回溯,撤销修改
}
}
}
*/
//=======代码如下:========
// 9*9的棋盘
static int[][] map = new int[9][9];
// 二维列表,存放所有空格的坐标,如:[[0,0], [8,0]]
static List<List<Integer>> spaces = new ArrayList<>();
// 标记变量:是否已正确填充所有空格
static boolean hasFinish = false;
public static void main(String[] args) {
// 初始化棋盘
Scanner in = new Scanner(System.in);
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
map[i][j] = in.nextInt();
// 将空格的坐标记录到spaces中
if (map[i][j] == 0) {
spaces.add(Arrays.asList(i,j));
}
}
}
// 调用回溯函数
backtrack(0);
// 输出填充完毕后的棋盘
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
System.out.print(map[i][j] + " ");
}
System.out.println();
}
}
/*
* 回溯函数
* 参数:index 当前要填充的空格在spaces的下标
*/
static void backtrack(int index) {
if (index == spaces.size()) {
hasFinish = true;
return;
}
// 获取空格的坐标
List<Integer> space = spaces.get(index);
int row = space.get(0);
int col = space.get(1);
// 遍历填入空格的可能值:1-9
for (int val = 1; val <= 9; val++) {
if (passCheck(row, col, val)) {
map[row][col] = val;
backtrack(index + 1);
if (hasFinish) {
return;
}
map[row][col] = 0;
}
}
}
// 检测在map[row][col] 填入 val,是否满足数独条件
static boolean passCheck(int row, int col, int val) {
// 检测所在行
for (int i = 0; i < 9; i++) {
if (map[row][i] == val)
return false;
}
// 检测所在列
for (int i = 0; i < 9; i++) {
if (map[i][col] == val)
return false;
}
// 检测所在3*3小宫格
int rowStart = row / 3 * 3; // 小宫格的行的最小值
int colStart = col / 3 * 3; // 小宫格的列的最小值
for (int i = rowStart; i < rowStart + 3; i++) {
for (int j = colStart; j < colStart + 3; j++) {
if (map[i][j] == val)
return false;
}
}
// 通过所有检测
return true;
}
}
