1.My BFS
class Solution {
public:
void solveSudoku(vector<vector<char>>& board) {
//BFS algorithm
//储存状态量,从左到右,从上到下。
vector<vector<int>> state_vars;
vector<vector<char>> board_tmp = board;
//状态量的初始化
for (int i = 1; i < 10; ++i){
vector<int> v(1,i);
state_vars.push_back(v);
}
vector<vector<int>> state_vars_tmp;
int empty_num = 0; //empty_num 为空格子的个数
//dp
for (int i = 0; i < 9; ++i){
for(int j = 0; j < 9; ++j){
if (board[i][j] == '.'){//外层的循环是dp的深度层数。
empty_num++;
for(int stInd = 0; stInd < state_vars.size(); ++stInd)
{
board_tmp = board;
if (empty_num > 1){
int depth = 0;
// cout<<"n level: "<<depth<<endl;
for (int ti = 0; ti < 9 && depth < empty_num-1; ++ti)
for(int tj = 0; tj < 9 && depth < empty_num-1; ++tj)
if (board_tmp[ti][tj] == '.'){
board_tmp[ti][tj] = (char)('0'+state_vars[stInd][depth]);//这个循环是填充已经遍历的了
depth ++;
}
}
bool isvalid = false;
for (int m = 1; m < 10; ++m){
vector<int> current_case = state_vars[stInd];
bool appeared = false;
//检查行列重复
for (int n = 0; n < 9; ++n){
//cout<<"r "<<board_tmp[i][n]<<(char)('0'+m);
if (board_tmp[i][n] == (char)('0'+m)){
appeared = true;
//cout<<" 重复:"<<m<<'('<<i<<','<<n<<')';
break;
}
if (board_tmp[n][j] == (char)('0'+m)){
appeared = true;
break;
}
}
//检查小九宫是否重复
int x = (int)(i/3)*3;
int y = (int)(j/3)*3;
// printf("(%d,%d)==(%d,%d)",i,j,x,y);
for (int q = 0; q < 3 && !appeared; ++q){
for (int p = 0; p < 3 && !appeared; ++p){
if (board_tmp[x+q][y+p] == (char)('0'+m)){
appeared = true;
}
}
}
//未出现的可做可行解
if (!appeared){
if (empty_num == 1)
current_case.pop_back();
current_case.push_back(m);
state_vars_tmp.push_back(current_case);
isvalid = true;
// for (int ii : current_case){
// cout<<ii;
// }
// cout<<endl;
}
}
if (empty_num == 1) break;
//cout<<"nus: "<<state_vars_tmp.size();
//cout<<endl;
}
state_vars = state_vars_tmp;
state_vars_tmp.clear();
// cout<<"f1 valid nums: "<<state_vars.size()<<endl;
}
}
}
// cout << "empty_num:"<<state_vars.size()<<endl;
int count = 0;
for (int i = 0; i < 9 && count < empty_num; ++i)
for(int j = 0; j < 9 && count < empty_num; ++j)
if (board[i][j] == '.')
{
board[i][j] = '0'+state_vars[0][count];
//cout<<"index:"<<count<<" "<<state_vars[0][count]<<" ";
count++;
}
}
- 一个很简洁的递归
bool check(vector<vector<char>> &board, int i, int j, char val)
{
int row = i - i%3, column = j - j%3;
for(int x=0; x<9; x++) if(board[x][j] == val) return false;
for(int y=0; y<9; y++) if(board[i][y] == val) return false;
for(int x=0; x<3; x++)
for(int y=0; y<3; y++)
if(board[row+x][column+y] == val) return false;
return true;
}
bool solveSudoku(vector<vector<char>> &board, int i, int j)
{
if(i==9) return true;
if(j==9) return solveSudoku(board, i+1, 0);
if(board[i][j] != '.') return solveSudoku(board, i, j+1);
for(char c='1'; c<='9'; c++)
{
if(check(board, i, j, c))
{
board[i][j] = c;
if(solveSudoku(board, i, j+1)) return true;
board[i][j] = '.';
}
}
return false;
}
public:
void solveSudoku(vector<vector<char>>& board) {
solveSudoku(board, 0, 0);
}
3.最快的,采用各种优化方法,比如唯一余法,的回溯法
class Solution {
struct cell // encapsulates a single cell on a Sudoku board
{
uint8_t value; // cell value 1..9 or 0 if unset
// number of possible (unconstrained) values for the cell
uint8_t numPossibilities;
// if bitset[v] is 1 then value can't be v
bitset<10> constraints;
cell() : value(0), numPossibilities(9),constraints() {};
};
array<array<cell,9>,9> cells;
// sets the value of the cell to [v]
// the function also propagates constraints to other cells and deduce new values where possible
bool set(int i, int j, int v)
{
// updating state of the cell
cell& c = cells[i][j];
if (c.value == v)
return true;
if (c.constraints[v])
return false;
c.constraints = bitset<10>(0x3FE); // all 1s
c.constraints.reset(v);
c.numPossibilities = 1;
c.value = v;
// propagating constraints
for (int k = 0; k<9; k++) {
// to the row:
if (i != k && !updateConstraints(k, j, v))
return false;
// to the column:
if (j != k && !updateConstraints(i, k, v))
return false;
// to the 3x3 square:
int ix = (i / 3) * 3 + k / 3;
int jx = (j / 3) * 3 + k % 3;
if (ix != i && jx != j && !updateConstraints(ix, jx, v))
return false;
}
return true;
}
// update constraints of the cell i,j by excluding possibility of 'excludedValue'
// once there's one possibility left the function recurses back into set()
bool updateConstraints(int i, int j, int excludedValue)
{
cell& c = cells[i][j];
if (c.constraints[excludedValue]) {
return true;
}
if (c.value == excludedValue) {
return false;
}
c.constraints.set(excludedValue);
if (--c.numPossibilities > 1)
return true;
for (int v = 1; v <= 9; v++) {
if (!c.constraints[v]) {
return set(i, j, v);
}
}
assert(false);
}
// backtracking state - list of empty cells
vector<pair<int, int>> bt;
// find values for empty cells
bool findValuesForEmptyCells()
{
// collecting all empty cells
bt.clear();
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (!cells[i][j].value)
bt.push_back(make_pair(i, j));
}
}
// making backtracking efficient by pre-sorting empty cells by numPossibilities
sort(bt.begin(), bt.end(), [this](const pair<int, int>&a, const pair<int, int>&b) {
return cells[a.first][a.second].numPossibilities < cells[b.first][b.second].numPossibilities; });
return backtrack(0);
}
// Finds value for all empty cells with index >=k
bool backtrack(int k)
{
if (k >= bt.size())
return true;
int i = bt[k].first;
int j = bt[k].second;
// fast path - only 1 possibility
if (cells[i][j].value)
return backtrack(k + 1);
auto constraints = cells[i][j].constraints;
// slow path >1 possibility.
// making snapshot of the state
array<array<cell,9>,9> snapshot(cells);
for (int v = 1; v <= 9; v++) {
if (!constraints[v]) {
if (set(i, j, v)) {
if (backtrack(k + 1))
return true;
}
// restoring from snapshot,
// note: computationally this is cheaper
// than alternative implementation with undoing the changes
cells = snapshot;
}
}
return false;
}
public:
void solveSudoku(vector<vector<char>> &board) {
cells = array<array<cell,9>,9>(); // clear array
// Decoding input board into the internal cell matrix.
// As we do it - constraints are propagated and even additional values are set as we go
// (in the case if it is possible to unambiguously deduce them).
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++) {
if (board[i][j] != '.' && !set(i, j, board[i][j] - '0'))
return; // sudoku is either incorrect or unsolvable
}
}
// if we're lucky we've already got a solution,
// however, if we have empty cells we need to use backtracking to fill them
if (!findValuesForEmptyCells())
return; // sudoku is unsolvable
// copying the solution back to the board
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++) {
if (cells[i][j].value)
board[i][j] = cells[i][j].value + '0';
}
}
}
};