题目:
Write a program to solve a Sudoku puzzle by filling the empty cells.
Empty cells are indicated by the character '.'
.
You may assume that there will be only one unique solution.
A sudoku puzzle...
...and its solution numbers marked in red.
代码:
class Solution { public: void solveSudoku(vector<vector<char> >& board) { vector<pair<int, int> > emptyCells; vector<set<char> > rowSet, colSet, matrixSet; set<char> row, col, matrix; for ( size_t i = 0 ; i < 9; ++i ) { row.clear(); col.clear(); matrix.clear(); for ( size_t j = 0 ; j < 9; ++j ) { if (board[i][j]!='.'){ row.insert(board[i][j]); } else{ emptyCells.push_back(make_pair(i, j)); } if (board[j][i]!='.') col.insert(board[j][i]); int r = j/3+(i/3)*3, c = j%3+(i%3)*3; if (board[r][c]!='.') matrix.insert(board[r][c]); } rowSet.push_back(row); colSet.push_back(col); matrixSet.push_back(matrix); } Solution::dfs(board, emptyCells, rowSet, colSet, matrixSet); } static bool dfs( vector<vector<char> >& board, vector<pair<int, int> >& emptyCell, vector<set<char> >& rowSet, vector<set<char> >& colSet, vector<set<char> >& matrixSet) { if ( emptyCell.empty() ) return true; int i = emptyCell.back().first; int j = emptyCell.back().second; for ( char v = '1'; v<='9' && !emptyCell.empty(); ++v ) { if (rowSet[i].find(v)==rowSet[i].end() && colSet[j].find(v)==colSet[j].end() && matrixSet[(i/3)*3+j/3].find(v)==matrixSet[(i/3)*3+j/3].end() ) { board[i][j]=v; rowSet[i].insert(v); colSet[j].insert(v); matrixSet[(i/3)*3+j/3].insert(v); emptyCell.pop_back(); if ( Solution::dfs(board, emptyCell, rowSet, colSet, matrixSet) ) { return true; } else { emptyCell.push_back(make_pair(i, j)); board[i][j] = '.'; rowSet[i].erase(v); colSet[j].erase(v); matrixSet[(i/3)*3+j/3].erase(v); } } } return false; } };
tips:
采用深搜模板。
主要思路走一遍board,得到三个set,一个vector
1. 三个set分别为每行、列、子模块已有的数字
2. 一个vector中存放着'.'的位置
每次处理一个'.',遍历1到9:
1. 如果满足数独的条件,就往下走一层
2. 如果1到9都不满足,则退回到上一层,重新选择上一个位置的元素
这里有一个思维陷阱:
emptyCell.pop_back(); if ( Solution::dfs(board, emptyCell, rowSet, colSet, matrixSet) ) { return true; } else { emptyCell.push_back(make_pair(i, j)); board[i][j] = '.'; rowSet[i].erase(v); colSet[j].erase(v); matrixSet[(i/3)*3+j/3].erase(v); }
注意:pop和push操作应该是对应的,之前一直以为可以不用push的操作,原因是忽略了一种情况:如果一个位置从1到9都不满足,那么必然要回溯到上一层;即,某一个位置的元素是可能遍历不止一次1到9的。
=================================
这里set的效率可能有些低,换一个hashmap的效率可能高一些。
class Solution { public: void solveSudoku(vector<vector<char> >& board) { vector<pair<int, int> > emptyCells; vector<map<char,bool> > rowSet, colSet, matrixSet; map<char,bool> row, col, matrix; for ( size_t i = 0 ; i < 9; ++i ) { for ( char v = '1' ; v <= '9'; ++v ) { row[v] = col[v] = matrix[v] = false; } for ( size_t j = 0 ; j < 9; ++j ) { if (board[i][j]!='.'){ row[board[i][j]] = true; } else{ emptyCells.push_back(make_pair(i, j)); } if (board[j][i]!='.') col[board[j][i]]=true; int r = j/3+(i/3)*3, c = j%3+(i%3)*3; if (board[r][c]!='.') matrix[board[r][c]]=true; } rowSet.push_back(row); colSet.push_back(col); matrixSet.push_back(matrix); } Solution::dfs(board, emptyCells, rowSet, colSet, matrixSet); } static bool dfs( vector<vector<char> >& board, vector<pair<int, int> >& emptyCell, vector<map<char,bool> >& rowSet, vector<map<char,bool> >& colSet, vector<map<char,bool> >& matrixSet) { if ( emptyCell.empty() ) return true; int i = emptyCell.back().first, j = emptyCell.back().second; for ( char v = '1'; v<='9'; ++v ) { if (!rowSet[i][v] && !colSet[j][v] && !matrixSet[(i/3)*3+j/3][v] ) { board[i][j] = v; rowSet[i][v] = colSet[j][v] = matrixSet[(i/3)*3+j/3][v] = true; emptyCell.pop_back(); if ( Solution::dfs(board, emptyCell, rowSet, colSet, matrixSet) ){ return true; } else{ emptyCell.push_back(make_pair(i, j)); rowSet[i][v] = colSet[j][v] = matrixSet[(i/3)*3+j/3][v] = false; } } } return false; } };
tips:都换成了hashmap,效率有所提升。
============================================
第二次过这道题,还是sub board那块内容调了几次,AC了。
class Solution { public: void solveSudoku(vector<vector<char> >& board) { // restore all blank positions vector<pair<int, int> > blanks; for ( int i=0; i<board.size(); ++i ) { for ( int j=0; j<board[i].size(); ++j ) { if ( board[i][j]=='.' ) blanks.push_back(make_pair(i, j)); } } Solution::dfs(board, blanks); } static bool dfs( vector<vector<char> >& board, vector<pair<int,int> >& blanks ) { if ( blanks.empty() ) return true; const int r = blanks.back().first; const int c = blanks.back().second; for ( char v='1'; v<='9'; ++v ) { bool valid = true; // check row & column & subBoard for ( int i=0; i<9; ++i ) { if ( board[r][i]==v || board[i][c]==v || board[i/3+(r/3)*3][i%3+(c/3)*3]==v ) { valid = false; break; } } if ( valid ) { board[r][c] = v; blanks.pop_back(); if ( Solution::dfs(board, blanks) ) return true; blanks.push_back(make_pair(r, c)); board[r][c] = '.'; } } return false; } };