题目描述:
编写一个程序,通过填充空格来解决数独问题。
数独的解法需 遵循如下规则:
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)
数独部分空格内已填入了数字,空白格用 '.' 表示。
来源:力扣(LeetCode)
思路:
1)代码随想录:时间复杂度高
学到的内容:字符的遍历循环:第一次用到!
for(char k = '1';k <= '9';k++)
这个想法,确实第一次想不到!
实际每一个backTrack中只修改了一个 '.',有多少个点就需要传入多少次!每次都是传入一个少了一个点的新二维数组!
如果走到最后 ' . '改完了,就在最后一层的多层for循环中返回,一层一层返回true,就结束了该方法!如果遇到了false;返回上一层继续改!
就是这块儿回溯的思路一开始没想清楚!
其他都是一样的,唯一没考虑到的就是 开始回溯的情况;还有一开始的boolean返回值!
已经出现了 每个位置都放不了的情况,就直接返回就好了!不用往下,boolean
for(int i = 0;i < 9;i++){
for(int j = 0;j < 9;j++){
if(board[i][j] == '.'){
for(char k = '1';k <= '9';k++){
if(isTrue(board,i,j,k)){
board[i][j] = k;
if (backTrack(board)) return true;
board[i][j] = '.';//回溯
}
}
return false;
}
}
}
return true;
2)力扣答案:
用数组实现位置的判断
但是该题不可避免的一个处理!
将递归方法的返回值设置为 boolean!
代码:
1)回溯:参考代码回想录
class Solution {
//不要结果集,只用更改棋盘即可
public void solveSudoku(char[][] board) {
//传入的即一个 类似棋盘的 二维数组,不用自己声明,模仿N皇后问题
backTrack(board);
}
//回溯方法;可以在原方法中进行
boolean backTrack(char[][] board){
//结束条件就是棋盘没有 . ;因为不知道原来有多少 .
for(int i = 0;i < 9;i++){
for(int j = 0;j < 9;j++){
if(board[i][j] == '.'){
for(char k = '1';k <= '9';k++){
if(isTrue(board,i,j,k)){
board[i][j] = k;
if (backTrack(board)) return true;
board[i][j] = '.';//回溯
}
}
return false;
}
}
}
return true;
}
//判断条件
/**
传入棋盘、行、列,也就是要放置的位置
value表示要放置的值!
*/
boolean isTrue(char[][] board,int row,int col,int value){
//同一行和同一列好判断
for(int i = 0;i < 9;i++){
if(board[row][i] == value) return false;
}
for(int i = 0;i < 9;i++){
if(board[i][col] == value) return false;
}
//3 * 3空间内的判断;也就是有 9个区域,使用 row和col判断所属的区域!
//确定for for循环的区间:0、3、6三个,怎么确定;使用 row - row % 3也可以
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(board[r + i][c + j] == value) return false;
}
}
return true;
}
}
2)力扣:用数组记录,某行某列或某块是否出现过某值
class Solution {
public void solveSudoku(char[][] board) {
// 三个布尔数组 表明 行, 列, 还有 3*3 的方格的数字是否被使用过
boolean[][] rowUsed = new boolean[9][10];
boolean[][] colUsed = new boolean[9][10];
boolean[][][] boxUsed = new boolean[3][3][10];
// 初始化
for(int row = 0; row < board.length; row++){
for(int col = 0; col < board[0].length; col++) {
if(board[row][col] == '.') continue;
int num = board[row][col] - '0';
rowUsed[row][num] = colUsed[col][num] = boxUsed[row/3][col/3][num] = true;
}
}
// 递归尝试填充数组
recusiveSolveSudoku(board, rowUsed, colUsed, boxUsed, 0, 0);
}
private boolean recusiveSolveSudoku(char[][]board, boolean[][]rowUsed, boolean[][]colUsed, boolean[][][]boxUsed, int row, int col){
// 边界校验, 如果已经填充完成, 返回true, 表示一切结束
if(col == board[0].length){
col = 0;
row++;
//在这儿实现 行的增加
if(row == board.length) return true;
}
// 是空则尝试填充, 否则跳过继续尝试填充下一个位置
if(board[row][col] == '.') {
// 尝试填充1~9
for(int num = 1; num <= 9; num++){
if(rowUsed[row][num] || colUsed[col][num] || boxUsed[row/3][col/3][num]) continue;
rowUsed[row][num] = true;
colUsed[col][num] = true;
boxUsed[row/3][col/3][num] = true;
board[row][col] = (char)('0' + num);
if(recusiveSolveSudoku(board, rowUsed, colUsed, boxUsed, row, col + 1)) return true;
board[row][col] = '.';
rowUsed[row][num] = false;
colUsed[col][num] = false;
boxUsed[row/3][col/3][num] = false;
}
} else {
//在这儿实现 列的增加,同上面递归处
return recusiveSolveSudoku(board, rowUsed, colUsed, boxUsed, row, col + 1);
}
return false;
}
}
作者:I_use_java
链接:https://leetcode-cn.com/problems/sudoku-solver/solution/hui-su-fa-jie-shu-du-by-i_use_python/
来源:力扣(LeetCode)