37.Sudoku Solver
Difficulty:Hard
Total Accepted:105.3K
Total Submissions:311.2K
https://leetcode.com/problems/sudoku-solver/description/
Write a program to solve a Sudoku puzzle by filling the empty cells.
A sudoku solution must satisfy all of the following rules:
Each of the digits 1-9 must occur exactly once in each row.
Each of the digits 1-9 must occur exactly once in each column.
Each of the the digits 1-9 must occur exactly once in each of the 9 3x3 sub-boxes of the grid.
Empty cells are indicated by the character ‘.’.
A sudoku puzzle…
…and its solution numbers marked in red.
Note:
The given board contain only digits 1-9 and the character ‘.’.
You may assume that the given Sudoku puzzle will have a single unique solution.
The given board size is always 9x9.
思路:利用回溯法
回溯法有通用解法的美称,对于很多问题,如迷宫等都有很好的效果。回溯算法实际上一个类似枚举的深度优先搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回(也就是递归返回),尝试别的路径。许多复杂的,规模较大的问题都可以使用回溯法,有“通用解题方法”的美称。回溯法说白了就是穷举法。回溯法一般用递归来解决。
递归思路:
- 读取数独的初始状态,填入sudoku变量
- 在读取数独的初始状态的同时,并初始化数字的可填区域,填入flag变量
- 在读取数独的初始状态的同时,更新数独的数字占用情况,填入rule变量
- 开始求解数独,进入首层递归
- 获取下一个可填区域的位置
- 若当前位置已超出期望,表明已得出数独的解,打印结果并回溯到上一层进行求解
- 查找当前位置的数字占用情况,对三条规则进行交集运算,得出下一个可填数。如果超出期望,回溯到上一层进行求解
- 修改当前位置的可填数,并更新对应数字的占用状态为已占用
- 以当前的坐标作为实参进入下一层递归,返回步骤5
- 修改当前位置的可填数,并更新对应数字的占用状态为未占用(失败,重新归为)
class Solution {
public:
bool flag[9][9] = { false };//对应位置的数字被确定
bool rule[3][9][9] = { false };//对应的行/列/块的某个数字是否已经出现过
int size = 0;
void solveSudoku(vector<vector<char>>& board) {
init(board);
solve(0, 0, board);
}
void solve(int row,int col,vector<vector<char>>& board) {
if ( col==9 ) {
col = 0;
row++;
}
while (row < 9 && flag[row][col++]) {//过掉已经确定的数字
if (col == 9) {
col = 0;
row++;
}
}
if (row == 9) {//已经全部位置确定
return;
}
while (1) {
board[row][col] = findNextValue(row,col,0,board);//假设该位置的值为某个数
if (board[row][col]!=-1) {
changeRule(row, col, true, board);
solve(row, ++col, board);
changeRule(row, col, true, board);
}
}
}
void init(vector<vector<char>>& board) {
size = board.size();
int value = 0;
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
if (board[i][j]!= '.') {
flag[i][j] = true;
value = board[i][j] - '0'-1;
rule[0][i][value] = true;
rule[1][j][value] = true;
rule[2][findBlockNum(i, j)][value] = true;
}
}
}
}
int findNextValue(int row,int col,int start, vector<vector<char>>& board) {
for (int i = start; i < board.size(); i++) {
if ( rule[0][row][i]||rule[1][col][i]||rule[2][findBlockNum(row,col)][i] )continue;
return i;
}
return -1;//未找到
}
void changeRule(int row,int col,bool B, vector<vector<char>>& board) {
int value = board[row][col] - '0' - 1;
rule[0][row][value] = B;
rule[1][col][value] = B;
rule[2][findBlockNum(row, col)][value] = B;
}
int findBlockNum(int row, int col) {
return (3 * (row / 3) + (col / 3));
}
};