内容介绍
编写一个程序,通过填充空格来解决数独问题。
数独的解法需 遵循如下规则:
- 数字
1-9
在每一行只能出现一次。- 数字
1-9
在每一列只能出现一次。- 数字
1-9
在每一个以粗实线分隔的3x3
宫内只能出现一次。(请参考示例图)数独部分空格内已填入了数字,空白格用
'.'
表示。示例 1:
输入:board = [["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"]] 解释:输入的数独如上图所示,唯一有效的解决方案如下所示:提示:
board.length == 9
board[i].length == 9
board[i][j]
是一位数字或者'.'
- 题目数据 保证 输入数独仅有一个解
完整代码
bool line[9][9];
bool column[9][9];
bool block[3][3][9];
bool valid;
int* spaces[81];
int spacesSize;void dfs(char** board, int pos) {if (pos == spacesSize) {valid = true;return;}int i = spaces[pos][0], j = spaces[pos][1];for (int digit = 0; digit < 9 && !valid; ++digit) {if (!line[i][digit] && !column[j][digit] && !block[i / 3][j / 3][digit]) {line[i][digit] = column[j][digit] = block[i / 3][j / 3][digit] = true;board[i][j] = digit + '0' + 1;dfs(board, pos + 1);line[i][digit] = column[j][digit] = block[i / 3][j / 3][digit] = false;}}
}void solveSudoku(char** board, int boardSize, int* boardColSize) {memset(line, false, sizeof(line));memset(column, false, sizeof(column));memset(block, false, sizeof(block));valid = false;spacesSize = 0;for (int i = 0; i < 9; ++i) {for (int j = 0; j < 9; ++j) {if (board[i][j] == '.') {spaces[spacesSize] = malloc(sizeof(int) * 2);spaces[spacesSize][0] = i;spaces[spacesSize++][1] = j;} else {int digit = board[i][j] - '0' - 1;line[i][digit] = column[j][digit] = block[i / 3][j / 3][digit] = true;}}}dfs(board, 0);
}
思路详解
方法概述
solveSudoku
:主方法,初始化数据结构并调用DFS方法来填充数独板。dfs
:递归方法,用于尝试填充数独板的每个空格。
数据结构
line
:一个二维布尔数组,用于标记每行中每个数字是否已经被使用。column
:一个二维布尔数组,用于标记每列中每个数字是否已经被使用。block
:一个三维布尔数组,用于标记每个3x3宫格中每个数字是否已经被使用。valid
:一个布尔变量,用于标记是否已经找到有效的数独解决方案。spaces
:一个指针数组,用于存储所有空格的位置。spacesSize
:一个整数,用于记录空格的数量。
解题步骤
初始化
- 使用
memset
函数将line
、column
和block
数组初始化为false
,表示所有数字都未被使用。 - 将
valid
变量设置为false
,表示尚未找到解决方案。 - 遍历数独板,对于每个元素:
- 如果是空格(即’.'),则记录该空格的位置到
spaces
数组,并增加spacesSize
。 - 如果是非空格,则更新
line
、column
和block
数组,标记该数字已被使用。
- 如果是空格(即’.'),则记录该空格的位置到
深度优先搜索(DFS)
- 递归方法
dfs
接收当前填充空格的位置pos
。 - 如果
pos
等于spacesSize
,说明所有空格都已填充,设置valid
为true
并返回。 - 对于当前空格位置,尝试填充数字1到9:
- 检查当前数字是否在当前行、当前列和当前3x3宫格中未被使用。
- 如果未被使用,则更新
line
、column
和block
数组,将当前数字标记为已使用,并在数独板上填充该数字。 - 递归调用
dfs
,尝试填充下一个空格。 - 如果递归调用后未找到解决方案,则回溯,撤销当前数字的填充,并继续尝试下一个数字。
解决方案
- 如果在DFS过程中找到了有效的解决方案,
valid
将被设置为true
,数独板将被填充完成。 - 如果所有可能的填充方式都尝试过后仍未找到解决方案,则数独无解。
总结
这段代码通过深度优先搜索算法和回溯策略来解决问题。它通过递归地尝试填充每个空格,并在每一步都检查是否违反了数独的规则,从而找到有效的解决方案。通过使用布尔数组来跟踪每个数字的使用情况,代码能够高效地进行检查和回溯。
知识点精炼
-
深度优先搜索(DFS):
- 使用递归方法实现DFS,探索数独所有可能的填充组合。
-
回溯算法:
- 在DFS中应用回溯,撤销之前的填充以探索新的可能性。
-
布尔数组:
- 使用布尔数组
line
、column
和block
来跟踪每个数字在行、列和宫格中的使用情况。
- 使用布尔数组
-
数独规则:
- 确保每行、每列和每个3x3宫格内的数字1至9不重复。
-
数组初始化:
- 使用
memset
函数初始化布尔数组,确保所有值初始为false
。
- 使用
-
动态内存分配:
- 使用
malloc
为spaces
数组分配内存,存储空格位置。
- 使用
-
ASCII转换:
- 通过字符与整数的ASCII转换,实现字符数字与整数的相互转换。
-
索引计算:
- 使用数组索引来访问和更新行、列和宫格的状态。
-
递归终止条件:
- 当所有空格都被填充时,递归终止,并标记找到有效解决方案。
-
状态重置:
- 在回溯过程中,撤销对行、列和宫格状态的更改,以便探索其他可能的填充。
-
全局变量:
- 使用全局变量
valid
来标记是否找到解决方案,以及spacesSize
来跟踪空格数量。
- 使用全局变量