来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sudoku-solver
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
37.编写一个程序,通过填充空格来解决数独问题。
数独的解法需 遵循如下规则:
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)
数独部分空格内已填入了数字,空白格用 ‘.’ 表示。
- 又是一道难题,只能通过题解来学习了。在解n皇后问题的时候,由于在每一行只能放置一个皇后,也就是说每次只需要在一行中的某一个位置进行修改值即可,所以只需要一个for循环就能解决每一行的放置问题;但是在解数独问题中,由于每一行的每个位置都需要填上数字,因此比n皇后问题更加复杂,需要用到两个for循环来解决问题,加上每个位置放置的数字有多种选择,所以实际上是三个for循环嵌套加上一个递归。与之前的回溯题目有点不太一样的是,之前的递归函数返回值一般都设置为void,这里递归函数的返回值设置为bool,因为题目说有唯一解,所以当找到一个符合要求的解时,就可以直接返回结束所有递归函数了。
- 具体看代码,代码还是相对比较清晰的,这些难题一般都是难在思路上,思路清晰了,代码看起来也不是很难。
//判断再board[row][col]位置上放val是否合适
bool isValid(int row, int col, char val, char** board, int boardSize) {
// 判断同行是否出现val
for (int i = 0; i < boardSize; i++) {
if (board[row][i] == val)
return false;
}
// 判断同列是否出现val
for (int i = 0; i < boardSize; i++) {
if (board[i][col] == val)
return false;
}
// 判断val所在3*3宫内是否出现val
int startRow = (row / 3) * 3;
int startCol = (col / 3) * 3;
for (int i = startRow; i < startRow + 3; i++) {
for (int j = startCol; i < startCol + 3; j++) {
if (board[i][j] == val)
return false;
}
}
return true;
}
bool backtracking(char** board, int boardSize) {
for (int i = 0; i < boardSize; i++) { //遍历行
for (int j = 0; j < boardSize; j++) { //遍历列
if (board[i][j] != '.') //如果不是空白格则跳过
continue;
for (char k = '1'; k <= '9'; k++) { //每个空白格可以选择的数字有9个
if (isValid(i, j, k, board, boardSize)) { //如果合法则再board[i][j]位置放置数字k
board[i][j] = k;
if (backtracking(board, boardSize)) { //如果找到合适的解则立即返回
return true;
}
board[i][j] = '.'; //回溯,撤销放置k
}
}
return false; //一个位置9种数字都不行的话则无解
}
}
return true; //能到这说明9*9宫格已经填满,即找到合适的解了
}
void solveSudoku(char** board, int boardSize, int* boardColSize){
boardColSize = malloc(sizeof(int) * boardSize);
for (int i = 0; i < boardSize; i++) {
boardColSize[i] = boardSize;
}
backtracking(board, boardSize);
}
- 一生之敌AddressSanitizer,代码又报错了,真的是无语。